display/gfx.h & buffer_producer.h: Start major refactor, highly WIP

This commit is contained in:
fincs 2018-08-29 00:55:09 +02:00
parent 10684e205a
commit f2f59c75c0
4 changed files with 113 additions and 203 deletions

View File

@ -1,36 +1,31 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
#include "../nvidia/ioctl.h" #include "../nvidia/fence.h"
typedef struct {
u32 is_valid;
nvioctl_fence nv_fences[4];
} PACKED BqFence;
typedef struct { typedef struct {
s32 left; s32 left;
s32 top; s32 top;
s32 right; s32 right;
s32 bottom; s32 bottom;
} PACKED BqRect; } BqRect;
typedef struct { typedef struct {
s64 timestamp; struct { s64 timestamp; } PACKED;
s32 isAutoTimestamp; s32 isAutoTimestamp;
BqRect crop; BqRect crop;
s32 scalingMode; s32 scalingMode;
u32 transform; // See the NATIVE_WINDOW_TRANSFORM_* enums. u32 transform; // See the NATIVE_WINDOW_TRANSFORM_* enums.
u32 stickyTransform; u32 stickyTransform;
u32 unk[2]; u32 unk[2];
BqFence fence; NvMultiFence fence;
} PACKED BqQueueBufferInput; } BqQueueBufferInput;
typedef struct { typedef struct {
u32 width; u32 width;
u32 height; u32 height;
u32 transformHint; u32 transformHint;
u32 numPendingBuffers; u32 numPendingBuffers;
} PACKED BqQueueBufferOutput; } BqQueueBufferOutput;
typedef struct { typedef struct {
u32 magic; u32 magic;
@ -76,18 +71,15 @@ typedef struct {
u32 unk_x68; u32 unk_x68;
u32 buffer_size1; u32 buffer_size1;
u32 unk_x70[0x33]; // Normally all-zero. u32 unk_x70[0x33]; // Normally all-zero.
u64 timestamp; struct { u64 timestamp; } PACKED; // unused
} PACKED data; } data;
} PACKED BqGraphicBuffer; } BqGraphicBuffer;
Result bqInitialize(Binder *session); Result bqRequestBuffer(Binder *b, s32 bufferIdx, BqGraphicBuffer *buf);
void bqExit(void); Result bqDequeueBuffer(Binder *b, bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf, NvMultiFence *fence);
Result bqDetachBuffer(Binder *b, s32 slot);
Result bqRequestBuffer(s32 bufferIdx, BqGraphicBuffer *buf); Result bqQueueBuffer(Binder *b, s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *output);
Result bqDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf, BqFence *fence); Result bqQuery(Binder *b, s32 what, s32* value);
Result bqDetachBuffer(s32 slot); Result bqConnect(Binder *b, s32 api, bool producerControlledByApp, BqQueueBufferOutput *output);
Result bqQueueBuffer(s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *output); Result bqDisconnect(Binder *b, s32 api);
Result bqQuery(s32 what, s32* value); Result bqSetPreallocatedBuffer(Binder *b, s32 buf, BqGraphicBuffer *input);
Result bqConnect(s32 api, bool producerControlledByApp, BqQueueBufferOutput *output);
Result bqDisconnect(s32 api);
Result bqGraphicBufferInit(s32 buf, BqGraphicBuffer *input);

View File

@ -17,7 +17,6 @@
/// GfxMode set by \ref gfxSetMode. The default is GfxMode_LinearDouble. Note that the text-console (see console.h) sets this to GfxMode_TiledDouble. /// GfxMode set by \ref gfxSetMode. The default is GfxMode_LinearDouble. Note that the text-console (see console.h) sets this to GfxMode_TiledDouble.
typedef enum typedef enum
{ {
GfxMode_TiledSingle, ///< Single-buffering with raw tiled (block-linear) framebuffer.
GfxMode_TiledDouble, ///< Double-buffering with raw tiled (block-linear) framebuffer. GfxMode_TiledDouble, ///< Double-buffering with raw tiled (block-linear) framebuffer.
GfxMode_LinearDouble ///< Double-buffering with linear framebuffer, which is transferred to the actual framebuffer by \ref gfxFlushBuffers(). GfxMode_LinearDouble ///< Double-buffering with linear framebuffer, which is transferred to the actual framebuffer by \ref gfxFlushBuffers().
} GfxMode; } GfxMode;

View File

@ -9,7 +9,8 @@
// Hence names/params etc here are based on Android IGraphicBufferProducer.cpp. // Hence names/params etc here are based on Android IGraphicBufferProducer.cpp.
// Based on an old version of the enum from the above .cpp. // Based on an old version of the enum from the above .cpp.
// Unknown whether all of these are correct for Switch. // https://android.googlesource.com/platform/frameworks/native/+/29a3e90879fd96404c971e7187cd0e05927bbce0/libs/gui/IGraphicBufferProducer.cpp#35
enum { enum {
/* 0x1 */ REQUEST_BUFFER = BINDER_FIRST_CALL_TRANSACTION, /* 0x1 */ REQUEST_BUFFER = BINDER_FIRST_CALL_TRANSACTION,
/* 0x2 */ SET_BUFFER_COUNT, /* 0x2 */ SET_BUFFER_COUNT,
@ -24,39 +25,23 @@ enum {
/* 0xB */ DISCONNECT, /* 0xB */ DISCONNECT,
/* 0xC */ SET_SIDEBAND_STREAM, /* 0xC */ SET_SIDEBAND_STREAM,
/* 0xD */ ALLOCATE_BUFFERS, /* 0xD */ ALLOCATE_BUFFERS,
/* 0xE */ GRAPHIC_BUFFER_INIT, // Custom Switch-specific command - unofficial name. /* 0xE */ SET_PREALLOCATED_BUFFER, // Custom Switch-specific command
}; };
static char g_bq_InterfaceDescriptor[] = "android.gui.IGraphicBufferProducer"; static const char g_bq_InterfaceDescriptor[] = "android.gui.IGraphicBufferProducer";
static Binder *g_bqBinderSession; Result bqRequestBuffer(Binder *b, s32 bufferIdx, BqGraphicBuffer *buf)
Result bqInitialize(Binder *session)
{
g_bqBinderSession = session;
return 0;
}
void bqExit(void)
{
g_bqBinderSession = NULL;
}
Result bqRequestBuffer(s32 bufferIdx, BqGraphicBuffer *buf)
{ {
Result rc; Result rc;
Parcel parcel, parcel_reply; Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel); parcelCreate(&parcel);
parcelCreate(&parcel_reply); parcelCreate(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor); parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor);
parcelWriteInt32(&parcel, bufferIdx); parcelWriteInt32(&parcel, bufferIdx);
rc = parcelTransact(g_bqBinderSession, REQUEST_BUFFER, &parcel, &parcel_reply); rc = parcelTransact(b, REQUEST_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
int nonNull = parcelReadInt32(&parcel_reply); int nonNull = parcelReadInt32(&parcel_reply);
@ -83,14 +68,11 @@ Result bqRequestBuffer(s32 bufferIdx, BqGraphicBuffer *buf)
return rc; return rc;
} }
Result bqDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf, BqFence *fence) Result bqDequeueBuffer(Binder *b, bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf, NvMultiFence *fence)
{ {
Result rc; Result rc;
Parcel parcel, parcel_reply; Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel); parcelCreate(&parcel);
parcelCreate(&parcel_reply); parcelCreate(&parcel_reply);
@ -102,7 +84,7 @@ Result bqDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage,
parcelWriteInt32(&parcel, format); parcelWriteInt32(&parcel, format);
parcelWriteUInt32(&parcel, usage); parcelWriteUInt32(&parcel, usage);
rc = parcelTransact(g_bqBinderSession, DEQUEUE_BUFFER, &parcel, &parcel_reply); rc = parcelTransact(b, DEQUEUE_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
*buf = parcelReadInt32(&parcel_reply); *buf = parcelReadInt32(&parcel_reply);
@ -112,11 +94,11 @@ Result bqDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage,
void* tmp_ptr; void* tmp_ptr;
tmp_ptr = parcelReadFlattenedObject(&parcel_reply, &tmp_size); tmp_ptr = parcelReadFlattenedObject(&parcel_reply, &tmp_size);
if (tmp_ptr == NULL || tmp_size != sizeof(BqFence)) if (tmp_ptr == NULL || tmp_size != sizeof(NvMultiFence))
return MAKERESULT(Module_Libnx, LibnxError_BadInput); return MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (fence) if (fence)
memcpy(fence, tmp_ptr, sizeof(BqFence)); memcpy(fence, tmp_ptr, sizeof(NvMultiFence));
} }
int result = parcelReadInt32(&parcel_reply); int result = parcelReadInt32(&parcel_reply);
@ -127,21 +109,18 @@ Result bqDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage,
return rc; return rc;
} }
Result bqDetachBuffer(s32 slot) Result bqDetachBuffer(Binder *b, s32 slot)
{ {
Result rc; Result rc;
Parcel parcel, parcel_reply; Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel); parcelCreate(&parcel);
parcelCreate(&parcel_reply); parcelCreate(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor); parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor);
parcelWriteInt32(&parcel, slot); parcelWriteInt32(&parcel, slot);
rc = parcelTransact(g_bqBinderSession, DETACH_BUFFER, &parcel, &parcel_reply); rc = parcelTransact(b, DETACH_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
//TODO: parse reply //TODO: parse reply
@ -150,14 +129,11 @@ Result bqDetachBuffer(s32 slot)
return rc; return rc;
} }
Result bqQueueBuffer(s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *output) Result bqQueueBuffer(Binder *b, s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *output)
{ {
Result rc; Result rc;
Parcel parcel, parcel_reply; Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel); parcelCreate(&parcel);
parcelCreate(&parcel_reply); parcelCreate(&parcel_reply);
@ -165,7 +141,7 @@ Result bqQueueBuffer(s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *ou
parcelWriteInt32(&parcel, buf); parcelWriteInt32(&parcel, buf);
parcelWriteFlattenedObject(&parcel, input, sizeof(*input)); parcelWriteFlattenedObject(&parcel, input, sizeof(*input));
rc = parcelTransact(g_bqBinderSession, QUEUE_BUFFER, &parcel, &parcel_reply); rc = parcelTransact(b, QUEUE_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
if (parcelReadData(&parcel_reply, output, sizeof(*output)) == NULL) if (parcelReadData(&parcel_reply, output, sizeof(*output)) == NULL)
@ -179,21 +155,18 @@ Result bqQueueBuffer(s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *ou
return rc; return rc;
} }
Result bqQuery(s32 what, s32* value) Result bqQuery(Binder *b, s32 what, s32* value)
{ {
Result rc; Result rc;
Parcel parcel, parcel_reply; Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel); parcelCreate(&parcel);
parcelCreate(&parcel_reply); parcelCreate(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor); parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor);
parcelWriteInt32(&parcel, what); parcelWriteInt32(&parcel, what);
rc = parcelTransact(g_bqBinderSession, QUERY, &parcel, &parcel_reply); rc = parcelTransact(b, QUERY, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
*value = parcelReadInt32(&parcel_reply); *value = parcelReadInt32(&parcel_reply);
@ -206,14 +179,11 @@ Result bqQuery(s32 what, s32* value)
return rc; return rc;
} }
Result bqConnect(s32 api, bool producerControlledByApp, BqQueueBufferOutput *output) Result bqConnect(Binder *b, s32 api, bool producerControlledByApp, BqQueueBufferOutput *output)
{ {
Result rc; Result rc;
Parcel parcel, parcel_reply; Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel); parcelCreate(&parcel);
parcelCreate(&parcel_reply); parcelCreate(&parcel_reply);
@ -224,7 +194,7 @@ Result bqConnect(s32 api, bool producerControlledByApp, BqQueueBufferOutput *out
parcelWriteInt32(&parcel, api); parcelWriteInt32(&parcel, api);
parcelWriteInt32(&parcel, producerControlledByApp); parcelWriteInt32(&parcel, producerControlledByApp);
rc = parcelTransact(g_bqBinderSession, CONNECT, &parcel, &parcel_reply); rc = parcelTransact(b, CONNECT, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
if (parcelReadData(&parcel_reply, output, sizeof(*output)) == NULL) if (parcelReadData(&parcel_reply, output, sizeof(*output)) == NULL)
@ -238,21 +208,18 @@ Result bqConnect(s32 api, bool producerControlledByApp, BqQueueBufferOutput *out
return rc; return rc;
} }
Result bqDisconnect(s32 api) Result bqDisconnect(Binder *b, s32 api)
{ {
Result rc; Result rc;
Parcel parcel, parcel_reply; Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel); parcelCreate(&parcel);
parcelCreate(&parcel_reply); parcelCreate(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor); parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor);
parcelWriteInt32(&parcel, api); parcelWriteInt32(&parcel, api);
rc = parcelTransact(g_bqBinderSession, DISCONNECT, &parcel, &parcel_reply); rc = parcelTransact(b, DISCONNECT, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
// TODO: parse reply // TODO: parse reply
@ -261,15 +228,12 @@ Result bqDisconnect(s32 api)
return rc; return rc;
} }
Result bqGraphicBufferInit(s32 buf, BqGraphicBuffer *input) Result bqSetPreallocatedBuffer(Binder *b, s32 buf, BqGraphicBuffer *input)
{ {
Result rc; Result rc;
Parcel parcel, parcel_reply; Parcel parcel, parcel_reply;
bool flag = 0; bool flag = 0;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel); parcelCreate(&parcel);
parcelCreate(&parcel_reply); parcelCreate(&parcel_reply);
@ -283,7 +247,7 @@ Result bqGraphicBufferInit(s32 buf, BqGraphicBuffer *input)
if (flag) if (flag)
parcelWriteFlattenedObject(&parcel, input, sizeof(BqGraphicBuffer)); parcelWriteFlattenedObject(&parcel, input, sizeof(BqGraphicBuffer));
rc = parcelTransact(g_bqBinderSession, GRAPHIC_BUFFER_INIT, &parcel, &parcel_reply); rc = parcelTransact(b, SET_PREALLOCATED_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
int result = parcelReadInt32(&parcel_reply); int result = parcelReadInt32(&parcel_reply);

View File

@ -20,11 +20,10 @@ static Binder g_gfxBinderSession;
static s32 g_gfxCurrentBuffer = 0; static s32 g_gfxCurrentBuffer = 0;
static s32 g_gfxCurrentProducerBuffer = 0; static s32 g_gfxCurrentProducerBuffer = 0;
static bool g_gfx_ProducerConnected = 0; static bool g_gfx_ProducerConnected = 0;
static bool g_gfx_ProducerSlotsRequested[2] = {0, 0}; static u32 g_gfx_ProducerSlotsRequested = 0;
static u8 *g_gfxFramebuf; static u8 *g_gfxFramebuf;
static size_t g_gfxFramebufSize; static size_t g_gfxFramebufSize;
static u32 g_gfxFramebufHandle; static u32 g_gfxFramebufHandle;
static BqFence g_gfx_DequeueBuffer_fence;
static BqQueueBufferOutput g_gfx_Connect_QueueBufferOutput; static BqQueueBufferOutput g_gfx_Connect_QueueBufferOutput;
static BqQueueBufferOutput g_gfx_QueueBuffer_QueueBufferOutput; static BqQueueBufferOutput g_gfx_QueueBuffer_QueueBufferOutput;
@ -51,7 +50,6 @@ static s32 g_gfx_autoresolution_docked_height;
extern u32 __nx_applet_type; extern u32 __nx_applet_type;
extern u32 g_nvgfx_totalframebufs; extern u32 g_nvgfx_totalframebufs;
extern nvioctl_fence g_nvgfx_nvhostgpu_gpfifo_fence;
//static Result _gfxGetDisplayResolution(u64 *width, u64 *height); //static Result _gfxGetDisplayResolution(u64 *width, u64 *height);
@ -64,17 +62,7 @@ static BqQueueBufferInput g_gfxQueueBufferData = {
.transform = NATIVE_WINDOW_TRANSFORM_FLIP_V, .transform = NATIVE_WINDOW_TRANSFORM_FLIP_V,
.stickyTransform = 0x0, .stickyTransform = 0x0,
.unk = {0x0, 0x1}, .unk = {0x0, 0x1},
.fence = {0},
.fence = {
.is_valid = 0x1,
.nv_fences = {
{
.id = 0xffffffff, //Official sw sets this to the output fence from the last nvioctlChannel_SubmitGPFIFO().
.value = 0x0,
},
{0xffffffff, 0x0}, {0xffffffff, 0x0}, {0xffffffff, 0x0},
},
}
}; };
// Some of this struct is based on tegra_dc_ext_flip_windowattr. // Some of this struct is based on tegra_dc_ext_flip_windowattr.
@ -108,50 +96,56 @@ static BqGraphicBuffer g_gfx_BufferInitData = {
} }
}; };
static Result _gfxDequeueBuffer(void) { NvMultiFence debugfence;
Result rc=0; Result debugfenceresult;
BqFence *fence = &g_gfx_DequeueBuffer_fence;
BqFence tmp_fence;
bool async=0;
if (g_gfxMode == GfxMode_TiledSingle) { static Result _gfxDequeueBuffer(void) {
g_gfxCurrentProducerBuffer = -1; if (g_gfxCurrentProducerBuffer >= 0)
return 0; return 0;
NvMultiFence fence;
s32 slot;
Result rc = bqDequeueBuffer(&g_gfxBinderSession, false, g_gfx_framebuf_width, g_gfx_framebuf_height, 0, 0x300, &slot, &fence);
if (R_FAILED(rc)) return rc;
if (!(g_gfx_ProducerSlotsRequested & BIT(slot))) {
rc = bqRequestBuffer(&g_gfxBinderSession, slot, NULL);
if (R_FAILED(rc))
return rc; // todo: cancelbuffer or something
g_gfx_ProducerSlotsRequested |= BIT(slot);
} }
memcpy(&tmp_fence, fence, sizeof(BqFence));//Offical sw waits on the fence from the previous DequeueBuffer call. Using the fence from the current DequeueBuffer call results in nvgfxEventWait() failing. debugfence = fence;
for (u32 i = 0; i < fence.num_fences; i ++) {
if ((s32)fence.fences[i].id >= 0) {
// todo: figure out why fencewait sucks
/*rc =*/ debugfenceresult = nvgfxEventWait(fence.fences[i].id, fence.fences[i].value, 0);
//if (R_FAILED(rc))
// break;
}
}
rc = bqDequeueBuffer(async, g_gfx_framebuf_width, g_gfx_framebuf_height, 0, 0x300, &g_gfxCurrentProducerBuffer, fence); if (R_SUCCEEDED(rc)) {
g_gfxCurrentProducerBuffer = slot;
//Only run nvgfxEventWait when the fence is valid and the id is not NO_FENCE. g_gfxCurrentBuffer = g_gfxCurrentProducerBuffer;
if (R_SUCCEEDED(rc) && tmp_fence.is_valid && tmp_fence.nv_fences[0].id!=0xffffffff) rc = nvgfxEventWait(tmp_fence.nv_fences[0].id, tmp_fence.nv_fences[0].value, -1); }
if (R_SUCCEEDED(rc)) g_gfxCurrentBuffer = (g_gfxCurrentBuffer + 1) & (g_nvgfx_totalframebufs-1);
//if (R_SUCCEEDED(rc)) rc = nvgfxSubmitGpfifo();
return rc; return rc;
} }
static Result _gfxQueueBuffer(s32 buf) { static Result _gfxQueueBuffer(void) {
Result rc=0; Result rc=0;
if (buf == -1) return 0; if (g_gfxCurrentProducerBuffer >= 0) {
rc = bqQueueBuffer(&g_gfxBinderSession, g_gfxCurrentProducerBuffer, &g_gfxQueueBufferData, &g_gfx_QueueBuffer_QueueBufferOutput);
g_gfxQueueBufferData.timestamp = svcGetSystemTick();//This is probably not the proper value for the timestamp, but shouldn't(?) matter. g_gfxCurrentProducerBuffer = -1;
//if (g_nvgfx_nvhostgpu_gpfifo_fence.id) memcpy(&g_gfxQueueBufferData.fence.nv_fences[0], &g_nvgfx_nvhostgpu_gpfifo_fence, sizeof(nvioctl_fence)); }
//if (g_nvgfx_nvhostgpu_gpfifo_fence.id) rc = nvgfxEventWait(g_nvgfx_nvhostgpu_gpfifo_fence.id, g_nvgfx_nvhostgpu_gpfifo_fence.value, -1);
if (R_FAILED(rc)) return rc;
rc = bqQueueBuffer(buf, &g_gfxQueueBufferData, &g_gfx_QueueBuffer_QueueBufferOutput);
if (R_FAILED(rc)) return rc;
return rc; return rc;
} }
Result gfxInitDefault(void) { Result gfxInitDefault(void) {
Result rc=0; Result rc=0;
u32 i=0;
if(g_gfxInitialized)return 0; if(g_gfxInitialized)return 0;
@ -167,8 +161,8 @@ Result gfxInitDefault(void) {
g_gfx_drawflip = true; g_gfx_drawflip = true;
g_gfxQueueBufferData.transform = NATIVE_WINDOW_TRANSFORM_FLIP_V; g_gfxQueueBufferData.transform = NATIVE_WINDOW_TRANSFORM_FLIP_V;
memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested)); //memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested));
memset(&g_gfx_DequeueBuffer_fence, 0, sizeof(g_gfx_DequeueBuffer_fence)); g_gfx_ProducerSlotsRequested = 0;
if (g_gfx_framebuf_width==0 || g_gfx_framebuf_height==0) { if (g_gfx_framebuf_width==0 || g_gfx_framebuf_height==0) {
g_gfx_framebuf_width = 1280; g_gfx_framebuf_width = 1280;
@ -214,68 +208,39 @@ Result gfxInitDefault(void) {
if (R_SUCCEEDED(rc)) rc = viCreateLayer(&g_gfxDisplay, &g_gfxLayer); if (R_SUCCEEDED(rc)) rc = viCreateLayer(&g_gfxDisplay, &g_gfxLayer);
if (R_SUCCEEDED(rc)) rc = viSetLayerScalingMode(&g_gfxLayer, ViScalingMode_Default);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
binderCreate(&g_gfxBinderSession, viGetSession_IHOSBinderDriverRelay()->handle, g_gfxLayer.igbp_binder_obj_id); binderCreate(&g_gfxBinderSession, viGetSession_IHOSBinderDriverRelay()->handle, g_gfxLayer.igbp_binder_obj_id);
rc = binderInitSession(&g_gfxBinderSession, 0x0f); rc = binderInitSession(&g_gfxBinderSession, 0x0f);
} }
if (R_SUCCEEDED(rc)) rc = viSetLayerScalingMode(&g_gfxLayer, ViScalingMode_Default);
if (R_SUCCEEDED(rc)) rc = bqConnect(&g_gfxBinderSession, NATIVE_WINDOW_API_CPU, 0, &g_gfx_Connect_QueueBufferOutput);
if (R_SUCCEEDED(rc)) g_gfx_ProducerConnected = true;
if (R_SUCCEEDED(rc)) rc = nvInitialize(); if (R_SUCCEEDED(rc)) rc = nvInitialize();
if (R_SUCCEEDED(rc)) rc = bqInitialize(&g_gfxBinderSession);
if (R_SUCCEEDED(rc)) rc = bqConnect(NATIVE_WINDOW_API_CPU, 0, &g_gfx_Connect_QueueBufferOutput);
if (R_SUCCEEDED(rc)) g_gfx_ProducerConnected = 1;
if (R_SUCCEEDED(rc)) rc = nvgfxInitialize(); if (R_SUCCEEDED(rc)) rc = nvgfxInitialize();
if (R_SUCCEEDED(rc)) rc = nvgfxGetFramebuffer(&g_gfxFramebuf, &g_gfxFramebufSize, &g_gfxFramebufHandle); if (R_SUCCEEDED(rc)) rc = nvgfxGetFramebuffer(&g_gfxFramebuf, &g_gfxFramebufSize, &g_gfxFramebufHandle);
if (R_SUCCEEDED(rc)) { //Official sw would use bqRequestBuffer() when required during swap-buffers/or similar, but that's not really an option here due to gfxSetDoubleBuffering().
for(i=0; i<2; i++) {
rc = _gfxDequeueBuffer();
if (R_FAILED(rc)) break;
rc = bqRequestBuffer(g_gfxCurrentProducerBuffer, NULL);
if (R_FAILED(rc)) break;
g_gfx_ProducerSlotsRequested[i] = 1;
//Officially, nvioctlNvmap_FromID() and nvioctlChannel_SubmitGPFIFO() are used here.
rc = _gfxQueueBuffer(g_gfxCurrentProducerBuffer);
if (R_FAILED(rc)) {
g_gfxCurrentProducerBuffer = -1;
break;
}
}
}
if (R_SUCCEEDED(rc)) rc = _gfxDequeueBuffer(); if (R_SUCCEEDED(rc)) rc = _gfxDequeueBuffer();
if (R_SUCCEEDED(rc)) { // todo: figure out if it's possible to wait for the 'Nintendo' logo screen to finish displaying (NSO, applet type: Application)
if (__nx_applet_type == AppletType_Application) { //It's unknown whether there's a better way to handle this.
svcSleepThread(2000000000);
}
else {
for(i=0; i<2; i++) gfxWaitForVsync();
}
}
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
_gfxQueueBuffer(g_gfxCurrentProducerBuffer); if (g_gfx_ProducerConnected) {
for(i=0; i<2; i++) { _gfxQueueBuffer();
if (g_gfx_ProducerSlotsRequested[i]) bqDetachBuffer(i); for(u32 i=0; i<32; i++) {
if (g_gfx_ProducerSlotsRequested & BIT(i)) bqDetachBuffer(&g_gfxBinderSession, i);
} }
if (g_gfx_ProducerConnected) bqDisconnect(NATIVE_WINDOW_API_CPU); bqDisconnect(&g_gfxBinderSession, NATIVE_WINDOW_API_CPU);
nvgfxExit(); nvgfxExit();
bqExit();
binderClose(&g_gfxBinderSession);
nvExit(); nvExit();
}
binderClose(&g_gfxBinderSession);
viCloseLayer(&g_gfxLayer); viCloseLayer(&g_gfxLayer);
viCloseDisplay(&g_gfxDisplay); viCloseDisplay(&g_gfxDisplay);
viExit(); viExit();
@ -298,7 +263,7 @@ Result gfxInitDefault(void) {
g_gfx_framebuf_width = 0; g_gfx_framebuf_width = 0;
g_gfx_framebuf_height = 0; g_gfx_framebuf_height = 0;
memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested)); g_gfx_ProducerSlotsRequested = 0;
} }
if (R_SUCCEEDED(rc)) g_gfxInitialized = 1; if (R_SUCCEEDED(rc)) g_gfxInitialized = 1;
@ -308,34 +273,29 @@ Result gfxInitDefault(void) {
void gfxExit(void) void gfxExit(void)
{ {
u32 i = 0;
if (!g_gfxInitialized) if (!g_gfxInitialized)
return; return;
_gfxQueueBuffer(g_gfxCurrentProducerBuffer); if (g_gfx_ProducerConnected) {
for (i=0; i<2; i++) { _gfxQueueBuffer();
if (g_gfx_ProducerSlotsRequested[i]) bqDetachBuffer(i); for(u32 i=0; i<32; i++) {
if (g_gfx_ProducerSlotsRequested & BIT(i)) bqDetachBuffer(&g_gfxBinderSession, i);
} }
if (g_gfx_ProducerConnected) bqDisconnect(2); bqDisconnect(&g_gfxBinderSession, NATIVE_WINDOW_API_CPU);
nvgfxExit(); nvgfxExit();
bqExit();
binderClose(&g_gfxBinderSession);
nvExit(); nvExit();
}
binderClose(&g_gfxBinderSession);
viCloseLayer(&g_gfxLayer); viCloseLayer(&g_gfxLayer);
viCloseDisplay(&g_gfxDisplay);
viExit();
if(g_gfxDisplayVsyncEvent != INVALID_HANDLE) { if(g_gfxDisplayVsyncEvent != INVALID_HANDLE) {
svcCloseHandle(g_gfxDisplayVsyncEvent); svcCloseHandle(g_gfxDisplayVsyncEvent);
g_gfxDisplayVsyncEvent = INVALID_HANDLE; g_gfxDisplayVsyncEvent = INVALID_HANDLE;
} }
viCloseDisplay(&g_gfxDisplay);
viExit();
free(g_gfxFramebufLinear); free(g_gfxFramebufLinear);
g_gfxFramebufLinear = NULL; g_gfxFramebufLinear = NULL;
@ -352,8 +312,7 @@ void gfxExit(void)
gfxConfigureAutoResolution(0, 0, 0, 0, 0); gfxConfigureAutoResolution(0, 0, 0, 0, 0);
memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested)); g_gfx_ProducerSlotsRequested = 0;
memset(&g_gfxQueueBufferData.crop, 0, sizeof(g_gfxQueueBufferData.crop)); memset(&g_gfxQueueBufferData.crop, 0, sizeof(g_gfxQueueBufferData.crop));
} }
@ -442,33 +401,29 @@ Result _gfxGraphicBufferInit(s32 buf, u32 nvmap_id, u32 nvmap_handle) {
g_gfx_BufferInitData.data.buffer_offset = g_gfx_singleframebuf_size*buf; g_gfx_BufferInitData.data.buffer_offset = g_gfx_singleframebuf_size*buf;
g_gfx_BufferInitData.data.timestamp = svcGetSystemTick(); g_gfx_BufferInitData.data.timestamp = svcGetSystemTick();
return bqGraphicBufferInit(buf, &g_gfx_BufferInitData); return bqSetPreallocatedBuffer(&g_gfxBinderSession, buf, &g_gfx_BufferInitData);
} }
static void _waitevent(Handle *handle) { static void _waitevent(Handle handle) {
Result rc=0, rc2=0; Result rc;
svcResetSignal(*handle);
do { do {
rc = svcWaitSynchronizationSingle(*handle, U64_MAX); rc = svcWaitSynchronizationSingle(handle, U64_MAX);
svcResetSignal(handle);
} while ((rc & 0x3FFFFF) == 0xFA01);
if (R_SUCCEEDED(rc)) if (R_FAILED(rc))
rc2 = svcResetSignal(*handle); fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadGfxEventWait));
} while(R_FAILED(rc) || (rc2 & 0x3FFFFF)==0xFA01);
if (R_FAILED(rc2)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadGfxEventWait));
} }
void gfxWaitForVsync(void) { void gfxWaitForVsync(void) {
_waitevent(&g_gfxDisplayVsyncEvent); _waitevent(g_gfxDisplayVsyncEvent);
} }
void gfxSwapBuffers(void) { void gfxSwapBuffers(void) {
Result rc=0; Result rc=0;
rc = _gfxQueueBuffer(g_gfxCurrentProducerBuffer); rc = _gfxQueueBuffer();
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadGfxQueueBuffer)); if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadGfxQueueBuffer));