diff --git a/nx/include/switch/gfx/buffer_producer.h b/nx/include/switch/gfx/buffer_producer.h index f59de6f4..7c54a9e2 100644 --- a/nx/include/switch/gfx/buffer_producer.h +++ b/nx/include/switch/gfx/buffer_producer.h @@ -1,10 +1,38 @@ +#pragma once + +#include + +typedef struct { + u32 unk_x0; + nvioctl_fence nv_fence; + u32 unk_xc[0x18>>2]; +} PACKED bufferProducerFence; + +typedef struct { + s64 timestamp; + s32 isAutoTimestamp; + u32 crop[4];//Rect + s32 scalingMode; + u32 transform; + u32 stickyTransform; + u32 unk[2]; + bufferProducerFence fence; +} PACKED bufferProducerQueueBufferInput; + +typedef struct { + u32 width; + u32 height; + u32 transformHint; + u32 numPendingBuffers; +} PACKED bufferProducerQueueBufferOutput; + Result bufferProducerInitialize(binderSession *session); void bufferProducerExit(); Result bufferProducerRequestBuffer(s32 bufferIdx); -Result bufferProducerDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf); +Result bufferProducerDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf, bufferProducerFence *fence); Result bufferProducerDetachBuffer(s32 slot); -Result bufferProducerQueueBuffer(s32 buf, u8 input[0x5c]); +Result bufferProducerQueueBuffer(s32 buf, bufferProducerQueueBufferInput *input, bufferProducerQueueBufferOutput *output); Result bufferProducerQuery(s32 what, s32* value); Result bufferProducerConnect(s32 api, bool producerControlledByApp); Result bufferProducerDisconnect(s32 api); diff --git a/nx/include/switch/gfx/nvioctl.h b/nx/include/switch/gfx/nvioctl.h index 297cba6f..6996839f 100644 --- a/nx/include/switch/gfx/nvioctl.h +++ b/nx/include/switch/gfx/nvioctl.h @@ -1,3 +1,5 @@ +#pragma once + typedef struct { u32 arch; // 0x120 (NVGPU_GPU_ARCH_GM200) u32 impl; // 0xB (NVGPU_GPU_IMPL_GM20B) diff --git a/nx/include/switch/gfx/parcel.h b/nx/include/switch/gfx/parcel.h index 98bc6509..1c7e2424 100644 --- a/nx/include/switch/gfx/parcel.h +++ b/nx/include/switch/gfx/parcel.h @@ -25,3 +25,6 @@ s32 parcelReadInt32(Parcel *ctx); u32 parcelReadUInt32(Parcel *ctx); void parcelWriteInterfaceToken(Parcel *ctx, const char *str); +void* parcelReadFlattenedObject(Parcel *ctx, size_t *size); +void* parcelWriteFlattenedObject(Parcel *ctx, void* data, size_t size); + diff --git a/nx/source/gfx/buffer_producer.c b/nx/source/gfx/buffer_producer.c index 06301cf1..3d4417c0 100644 --- a/nx/source/gfx/buffer_producer.c +++ b/nx/source/gfx/buffer_producer.c @@ -74,7 +74,7 @@ Result bufferProducerRequestBuffer(s32 bufferIdx) return rc; } -Result bufferProducerDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf) +Result bufferProducerDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf, bufferProducerFence *fence) { Result rc; Parcel parcel, parcel_reply; @@ -96,8 +96,20 @@ Result bufferProducerDequeueBuffer(bool async, u32 width, u32 height, s32 format rc = parcelTransact(g_bufferProducerBinderSession, DEQUEUE_BUFFER, &parcel, &parcel_reply); if (R_SUCCEEDED(rc)) { - // TODO: parse reply *buf = parcelReadInt32(&parcel_reply); + + if(parcelReadInt32(&parcel_reply)) { + size_t tmpsize=0; + void* tmp_ptr; + + tmp_ptr = parcelReadFlattenedObject(&parcel_reply, &tmpsize); + if (tmp_ptr==NULL || tmpsize!=0x24) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT); + if (fence) memcpy(fence, tmp_ptr, 0x24); + } + + int result = parcelReadInt32(&parcel_reply); + if (result != 0) + rc = MAKERESULT(MODULE_LIBNX, LIBNX_BUFFERPRODUCER_ERROR); } return rc; @@ -126,7 +138,7 @@ Result bufferProducerDetachBuffer(s32 slot) return rc; } -Result bufferProducerQueueBuffer(s32 buf, u8 input[0x5c]) +Result bufferProducerQueueBuffer(s32 buf, bufferProducerQueueBufferInput *input, bufferProducerQueueBufferOutput *output) { Result rc; Parcel parcel, parcel_reply; @@ -139,12 +151,16 @@ Result bufferProducerQueueBuffer(s32 buf, u8 input[0x5c]) parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor); parcelWriteInt32(&parcel, buf); - parcelWriteData(&parcel, input, 0x5c); + parcelWriteFlattenedObject(&parcel, input, sizeof(bufferProducerQueueBufferInput)); rc = parcelTransact(g_bufferProducerBinderSession, QUEUE_BUFFER, &parcel, &parcel_reply); if (R_SUCCEEDED(rc)) { - //TODO: parse reply + if (parcelReadData(&parcel_reply, output, sizeof(bufferProducerQueueBufferOutput))==NULL) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT); + + int result = parcelReadInt32(&parcel_reply); + if (result != 0) + rc = MAKERESULT(MODULE_LIBNX, LIBNX_BUFFERPRODUCER_ERROR); } return rc; diff --git a/nx/source/gfx/gfx.c b/nx/source/gfx/gfx.c index ef566cdc..52b6cc65 100644 --- a/nx/source/gfx/gfx.c +++ b/nx/source/gfx/gfx.c @@ -23,16 +23,26 @@ extern u32 __nx_applet_type; extern u32 g_nvgfx_totalframebufs; extern size_t g_nvgfx_singleframebuf_size; -static u32 g_gfxQueueBufferData[0x5c>>2] = { -0x54, 0x0, -0x0, 0x0, //u64 timestamp -0x1, 0x0, 0x0, -0x0, 0x0, 0x0, 0x2, -0x0, 0x0, 0x1, 0x1, -0x42, -0x13f4, -0xffffffff, 0x0, -0xffffffff, 0x0, 0xffffffff, 0x0}; +static bufferProducerQueueBufferInput g_gfxQueueBufferData = { + .timestamp = 0x0, + .isAutoTimestamp = 0x1, + .crop = {0x0, 0x0, 0x0, 0x0}, + .scalingMode = 0x0, + .transform = 0x2, + .stickyTransform = 0x0, + /*.unk = {0x0, 0x1}, + + .fence = { + .unk_x0 = 0x1, + .nv_fence = { + .id = 0x42, + .value = 0x13f4, + }, + .unk_xc = { + 0xffffffff, 0x0, 0xffffffff, 0x0, 0xffffffff, 0x0 + }, + }*/ +}; static Result _gfxGetNativeWindowID(u8 *buf, u64 size, s32 *out_ID) { u32 *bufptr = (u32*)buf; @@ -49,7 +59,7 @@ static Result _gfxGetNativeWindowID(u8 *buf, u64 size, s32 *out_ID) { return 0; } -static Result _gfxDequeueBuffer() { +static Result _gfxDequeueBuffer(bufferProducerFence *fence) { Result rc=0; if (!g_gfxDoubleBuf) { @@ -57,7 +67,7 @@ static Result _gfxDequeueBuffer() { return 0; } - rc = bufferProducerDequeueBuffer(/*1*/0, 1280, 720, 0, 0x300, &g_gfxCurrentProducerBuffer); + rc = bufferProducerDequeueBuffer(/*1*/0, 1280, 720, 0, 0x300, &g_gfxCurrentProducerBuffer, fence); if (R_SUCCEEDED(rc)) g_gfxCurrentBuffer = (g_gfxCurrentBuffer + 1) & (g_nvgfx_totalframebufs-1); @@ -66,19 +76,18 @@ static Result _gfxDequeueBuffer() { static Result _gfxQueueBuffer(s32 buf) { Result rc=0; - u64 *ptr64 = (u64*)&g_gfxQueueBufferData; if (buf == -1) return 0; - ptr64[1] = svcGetSystemTick();//Unknown what is actually used for timestamp, but shouldn't(?) matter. + g_gfxQueueBufferData.timestamp = svcGetSystemTick();//This is probably not the proper value for the timestamp, but shouldn't(?) matter. - rc = bufferProducerQueueBuffer(buf, (u8*)g_gfxQueueBufferData); + rc = bufferProducerQueueBuffer(buf, &g_gfxQueueBufferData, NULL); if (R_FAILED(rc)) return rc; - /*if(buf==0) { - g_gfxQueueBufferData[0x10]+= 0x6; + /*if(buf==0) {// + g_gfxQueueBufferData.nv_fence.value+= 0x6; } else { - g_gfxQueueBufferData[0x10]+= 0x7; + g_gfxQueueBufferData.nv_fence.value+= 0x7; }*/ return rc; @@ -133,7 +142,7 @@ static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 L if (R_SUCCEEDED(rc)) { for(i=0; i<2; i++) { - rc = _gfxDequeueBuffer(); + rc = _gfxDequeueBuffer(NULL); if (R_FAILED(rc)) break; rc = bufferProducerRequestBuffer(g_gfxCurrentProducerBuffer); @@ -153,11 +162,13 @@ static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 L if (R_SUCCEEDED(rc)) rc = nvgfxEventInit(); - if (R_SUCCEEDED(rc)) rc = _gfxDequeueBuffer(); + if (R_SUCCEEDED(rc)) svcSleepThread(3000000000); - if (R_SUCCEEDED(rc)) { //Workaround a gfx display issue. + if (R_SUCCEEDED(rc)) rc = _gfxDequeueBuffer(NULL); + + /*if (R_SUCCEEDED(rc)) { //Workaround a gfx display issue. for(i=0; i<2; i++)gfxWaitForVsync(); - } + }*/ if (R_FAILED(rc)) { _gfxQueueBuffer(g_gfxCurrentProducerBuffer); @@ -257,10 +268,20 @@ void gfxExit(void) { memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested)); } +static void _waitevent(Handle *handle) { + s32 tmpindex=0; + Result rc=0, rc2=0; + + do { + rc = svcWaitSynchronization(&tmpindex, handle, 1, U64_MAX); + if (R_SUCCEEDED(rc)) rc2 = svcResetSignal(*handle); + } while(R_FAILED(rc) || (rc2 & 0x3FFFFF)==0xFA01); + + if (R_FAILED(rc2)) fatalSimple(rc2); +} + void gfxWaitForVsync() { - s32 tmp = 0; - svcWaitSynchronization(&tmp, &g_gfxDisplayVsyncEvent, 1, U64_MAX); - svcClearEvent(g_gfxDisplayVsyncEvent); + _waitevent(&g_gfxDisplayVsyncEvent); } void gfxSwapBuffers() { @@ -268,7 +289,7 @@ void gfxSwapBuffers() { rc = _gfxQueueBuffer(g_gfxCurrentProducerBuffer); - if (R_SUCCEEDED(rc)) rc = _gfxDequeueBuffer(); + if (R_SUCCEEDED(rc)) rc = _gfxDequeueBuffer(NULL); if (R_FAILED(rc)) fatalSimple(rc); } diff --git a/nx/source/gfx/parcel.c b/nx/source/gfx/parcel.c index 2862f1a2..4a03361a 100644 --- a/nx/source/gfx/parcel.c +++ b/nx/source/gfx/parcel.c @@ -142,3 +142,22 @@ u32 parcelReadUInt32(Parcel *ctx) { parcelReadData(ctx, &val, sizeof(val)); return val; } + +void* parcelReadFlattenedObject(Parcel *ctx, size_t *size) { + s32 len = parcelReadInt32(ctx); + s32 fd_count = parcelReadInt32(ctx); + + if (size) *size = (u32)len; + + if(fd_count!=0)return NULL;//Not going to support fds. + + return parcelReadData(ctx, NULL, len); +} + +void* parcelWriteFlattenedObject(Parcel *ctx, void* data, size_t size) { + parcelWriteInt32(ctx, size);//len + parcelWriteInt32(ctx, 0);//fd_count + + return parcelWriteData(ctx, data, size); +} +