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

View File

@ -9,7 +9,8 @@
// Hence names/params etc here are based on Android IGraphicBufferProducer.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 {
/* 0x1 */ REQUEST_BUFFER = BINDER_FIRST_CALL_TRANSACTION,
/* 0x2 */ SET_BUFFER_COUNT,
@ -24,39 +25,23 @@ enum {
/* 0xB */ DISCONNECT,
/* 0xC */ SET_SIDEBAND_STREAM,
/* 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 bqInitialize(Binder *session)
{
g_bqBinderSession = session;
return 0;
}
void bqExit(void)
{
g_bqBinderSession = NULL;
}
Result bqRequestBuffer(s32 bufferIdx, BqGraphicBuffer *buf)
Result bqRequestBuffer(Binder *b, s32 bufferIdx, BqGraphicBuffer *buf)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel);
parcelCreate(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor);
parcelWriteInt32(&parcel, bufferIdx);
rc = parcelTransact(g_bqBinderSession, REQUEST_BUFFER, &parcel, &parcel_reply);
rc = parcelTransact(b, REQUEST_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) {
int nonNull = parcelReadInt32(&parcel_reply);
@ -83,14 +68,11 @@ Result bqRequestBuffer(s32 bufferIdx, BqGraphicBuffer *buf)
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;
Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel);
parcelCreate(&parcel_reply);
@ -102,7 +84,7 @@ Result bqDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage,
parcelWriteInt32(&parcel, format);
parcelWriteUInt32(&parcel, usage);
rc = parcelTransact(g_bqBinderSession, DEQUEUE_BUFFER, &parcel, &parcel_reply);
rc = parcelTransact(b, DEQUEUE_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) {
*buf = parcelReadInt32(&parcel_reply);
@ -112,11 +94,11 @@ Result bqDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage,
void* tmp_ptr;
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);
if (fence)
memcpy(fence, tmp_ptr, sizeof(BqFence));
memcpy(fence, tmp_ptr, sizeof(NvMultiFence));
}
int result = parcelReadInt32(&parcel_reply);
@ -127,21 +109,18 @@ Result bqDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage,
return rc;
}
Result bqDetachBuffer(s32 slot)
Result bqDetachBuffer(Binder *b, s32 slot)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel);
parcelCreate(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor);
parcelWriteInt32(&parcel, slot);
rc = parcelTransact(g_bqBinderSession, DETACH_BUFFER, &parcel, &parcel_reply);
rc = parcelTransact(b, DETACH_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) {
//TODO: parse reply
@ -150,14 +129,11 @@ Result bqDetachBuffer(s32 slot)
return rc;
}
Result bqQueueBuffer(s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *output)
Result bqQueueBuffer(Binder *b, s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *output)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel);
parcelCreate(&parcel_reply);
@ -165,7 +141,7 @@ Result bqQueueBuffer(s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *ou
parcelWriteInt32(&parcel, buf);
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 (parcelReadData(&parcel_reply, output, sizeof(*output)) == NULL)
@ -179,21 +155,18 @@ Result bqQueueBuffer(s32 buf, BqQueueBufferInput *input, BqQueueBufferOutput *ou
return rc;
}
Result bqQuery(s32 what, s32* value)
Result bqQuery(Binder *b, s32 what, s32* value)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel);
parcelCreate(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor);
parcelWriteInt32(&parcel, what);
rc = parcelTransact(g_bqBinderSession, QUERY, &parcel, &parcel_reply);
rc = parcelTransact(b, QUERY, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) {
*value = parcelReadInt32(&parcel_reply);
@ -206,14 +179,11 @@ Result bqQuery(s32 what, s32* value)
return rc;
}
Result bqConnect(s32 api, bool producerControlledByApp, BqQueueBufferOutput *output)
Result bqConnect(Binder *b, s32 api, bool producerControlledByApp, BqQueueBufferOutput *output)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel);
parcelCreate(&parcel_reply);
@ -224,7 +194,7 @@ Result bqConnect(s32 api, bool producerControlledByApp, BqQueueBufferOutput *out
parcelWriteInt32(&parcel, api);
parcelWriteInt32(&parcel, producerControlledByApp);
rc = parcelTransact(g_bqBinderSession, CONNECT, &parcel, &parcel_reply);
rc = parcelTransact(b, CONNECT, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) {
if (parcelReadData(&parcel_reply, output, sizeof(*output)) == NULL)
@ -238,21 +208,18 @@ Result bqConnect(s32 api, bool producerControlledByApp, BqQueueBufferOutput *out
return rc;
}
Result bqDisconnect(s32 api)
Result bqDisconnect(Binder *b, s32 api)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel);
parcelCreate(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bq_InterfaceDescriptor);
parcelWriteInt32(&parcel, api);
rc = parcelTransact(g_bqBinderSession, DISCONNECT, &parcel, &parcel_reply);
rc = parcelTransact(b, DISCONNECT, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) {
// TODO: parse reply
@ -261,15 +228,12 @@ Result bqDisconnect(s32 api)
return rc;
}
Result bqGraphicBufferInit(s32 buf, BqGraphicBuffer *input)
Result bqSetPreallocatedBuffer(Binder *b, s32 buf, BqGraphicBuffer *input)
{
Result rc;
Parcel parcel, parcel_reply;
bool flag = 0;
if (g_bqBinderSession == NULL)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
parcelCreate(&parcel);
parcelCreate(&parcel_reply);
@ -283,7 +247,7 @@ Result bqGraphicBufferInit(s32 buf, BqGraphicBuffer *input)
if (flag)
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)) {
int result = parcelReadInt32(&parcel_reply);

View File

@ -20,11 +20,10 @@ static Binder g_gfxBinderSession;
static s32 g_gfxCurrentBuffer = 0;
static s32 g_gfxCurrentProducerBuffer = 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 size_t g_gfxFramebufSize;
static u32 g_gfxFramebufHandle;
static BqFence g_gfx_DequeueBuffer_fence;
static BqQueueBufferOutput g_gfx_Connect_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 g_nvgfx_totalframebufs;
extern nvioctl_fence g_nvgfx_nvhostgpu_gpfifo_fence;
//static Result _gfxGetDisplayResolution(u64 *width, u64 *height);
@ -64,17 +62,7 @@ static BqQueueBufferInput g_gfxQueueBufferData = {
.transform = NATIVE_WINDOW_TRANSFORM_FLIP_V,
.stickyTransform = 0x0,
.unk = {0x0, 0x1},
.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},
},
}
.fence = {0},
};
// 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) {
Result rc=0;
BqFence *fence = &g_gfx_DequeueBuffer_fence;
BqFence tmp_fence;
bool async=0;
NvMultiFence debugfence;
Result debugfenceresult;
if (g_gfxMode == GfxMode_TiledSingle) {
g_gfxCurrentProducerBuffer = -1;
static Result _gfxDequeueBuffer(void) {
if (g_gfxCurrentProducerBuffer >= 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);
//Only run nvgfxEventWait when the fence is valid and the id is not NO_FENCE.
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();
if (R_SUCCEEDED(rc)) {
g_gfxCurrentProducerBuffer = slot;
g_gfxCurrentBuffer = g_gfxCurrentProducerBuffer;
}
return rc;
}
static Result _gfxQueueBuffer(s32 buf) {
static Result _gfxQueueBuffer(void) {
Result rc=0;
if (buf == -1) return 0;
g_gfxQueueBufferData.timestamp = svcGetSystemTick();//This is probably not the proper value for the timestamp, but shouldn't(?) matter.
//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;
if (g_gfxCurrentProducerBuffer >= 0) {
rc = bqQueueBuffer(&g_gfxBinderSession, g_gfxCurrentProducerBuffer, &g_gfxQueueBufferData, &g_gfx_QueueBuffer_QueueBufferOutput);
g_gfxCurrentProducerBuffer = -1;
}
return rc;
}
Result gfxInitDefault(void) {
Result rc=0;
u32 i=0;
if(g_gfxInitialized)return 0;
@ -167,8 +161,8 @@ Result gfxInitDefault(void) {
g_gfx_drawflip = true;
g_gfxQueueBufferData.transform = NATIVE_WINDOW_TRANSFORM_FLIP_V;
memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested));
memset(&g_gfx_DequeueBuffer_fence, 0, sizeof(g_gfx_DequeueBuffer_fence));
//memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested));
g_gfx_ProducerSlotsRequested = 0;
if (g_gfx_framebuf_width==0 || g_gfx_framebuf_height==0) {
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 = viSetLayerScalingMode(&g_gfxLayer, ViScalingMode_Default);
if (R_SUCCEEDED(rc)) {
binderCreate(&g_gfxBinderSession, viGetSession_IHOSBinderDriverRelay()->handle, g_gfxLayer.igbp_binder_obj_id);
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 = 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 = 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)) {
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();
}
}
// todo: figure out if it's possible to wait for the 'Nintendo' logo screen to finish displaying (NSO, applet type: Application)
if (R_FAILED(rc)) {
_gfxQueueBuffer(g_gfxCurrentProducerBuffer);
for(i=0; i<2; i++) {
if (g_gfx_ProducerSlotsRequested[i]) bqDetachBuffer(i);
if (g_gfx_ProducerConnected) {
_gfxQueueBuffer();
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();
bqExit();
binderClose(&g_gfxBinderSession);
nvExit();
}
binderClose(&g_gfxBinderSession);
viCloseLayer(&g_gfxLayer);
viCloseDisplay(&g_gfxDisplay);
viExit();
@ -298,7 +263,7 @@ Result gfxInitDefault(void) {
g_gfx_framebuf_width = 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;
@ -308,34 +273,29 @@ Result gfxInitDefault(void) {
void gfxExit(void)
{
u32 i = 0;
if (!g_gfxInitialized)
return;
_gfxQueueBuffer(g_gfxCurrentProducerBuffer);
for (i=0; i<2; i++) {
if (g_gfx_ProducerSlotsRequested[i]) bqDetachBuffer(i);
if (g_gfx_ProducerConnected) {
_gfxQueueBuffer();
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();
bqExit();
binderClose(&g_gfxBinderSession);
nvExit();
}
binderClose(&g_gfxBinderSession);
viCloseLayer(&g_gfxLayer);
viCloseDisplay(&g_gfxDisplay);
viExit();
if(g_gfxDisplayVsyncEvent != INVALID_HANDLE) {
svcCloseHandle(g_gfxDisplayVsyncEvent);
g_gfxDisplayVsyncEvent = INVALID_HANDLE;
}
viCloseDisplay(&g_gfxDisplay);
viExit();
free(g_gfxFramebufLinear);
g_gfxFramebufLinear = NULL;
@ -352,8 +312,7 @@ void gfxExit(void)
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));
}
@ -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.timestamp = svcGetSystemTick();
return bqGraphicBufferInit(buf, &g_gfx_BufferInitData);
return bqSetPreallocatedBuffer(&g_gfxBinderSession, buf, &g_gfx_BufferInitData);
}
static void _waitevent(Handle *handle) {
Result rc=0, rc2=0;
svcResetSignal(*handle);
static void _waitevent(Handle handle) {
Result rc;
do {
rc = svcWaitSynchronizationSingle(*handle, U64_MAX);
rc = svcWaitSynchronizationSingle(handle, U64_MAX);
svcResetSignal(handle);
} while ((rc & 0x3FFFFF) == 0xFA01);
if (R_SUCCEEDED(rc))
rc2 = svcResetSignal(*handle);
} while(R_FAILED(rc) || (rc2 & 0x3FFFFF)==0xFA01);
if (R_FAILED(rc2)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadGfxEventWait));
if (R_FAILED(rc))
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadGfxEventWait));
}
void gfxWaitForVsync(void) {
_waitevent(&g_gfxDisplayVsyncEvent);
_waitevent(g_gfxDisplayVsyncEvent);
}
void gfxSwapBuffers(void) {
Result rc=0;
rc = _gfxQueueBuffer(g_gfxCurrentProducerBuffer);
rc = _gfxQueueBuffer();
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadGfxQueueBuffer));