mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-23 13:22:40 +02:00
display/gfx.h & buffer_producer.h: Start major refactor, highly WIP
This commit is contained in:
parent
10684e205a
commit
f2f59c75c0
@ -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);
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user