mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
285 lines
8.5 KiB
C
285 lines
8.5 KiB
C
#include <string.h>
|
|
#include "types.h"
|
|
#include "result.h"
|
|
#include "gfx/parcel.h"
|
|
#include "gfx/buffer_producer.h"
|
|
|
|
|
|
// This implements the version of Android IGraphicBufferProducer used by Switch.
|
|
// 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.
|
|
enum {
|
|
/* 0x1 */ REQUEST_BUFFER = BINDER_FIRST_CALL_TRANSACTION,
|
|
/* 0x2 */ SET_BUFFER_COUNT,
|
|
/* 0x3 */ DEQUEUE_BUFFER,
|
|
/* 0x4 */ DETACH_BUFFER,
|
|
/* 0x5 */ DETACH_NEXT_BUFFER,
|
|
/* 0x6 */ ATTACH_BUFFER,
|
|
/* 0x7 */ QUEUE_BUFFER,
|
|
/* 0x8 */ CANCEL_BUFFER,
|
|
/* 0x9 */ QUERY,
|
|
/* 0xA */ CONNECT,
|
|
/* 0xB */ DISCONNECT,
|
|
/* 0xC */ SET_SIDEBAND_STREAM,
|
|
/* 0xD */ ALLOCATE_BUFFERS,
|
|
/* 0xE */ GRAPHIC_BUFFER_INIT, // Custom Switch-specific command - unofficial name.
|
|
};
|
|
|
|
static char g_bufferProducer_InterfaceDescriptor[] = "android.gui.IGraphicBufferProducer";
|
|
|
|
static Binder *g_bufferProducerBinderSession;
|
|
|
|
Result bufferProducerInitialize(Binder *session)
|
|
{
|
|
g_bufferProducerBinderSession = session;
|
|
return 0;
|
|
}
|
|
|
|
void bufferProducerExit(void)
|
|
{
|
|
g_bufferProducerBinderSession = NULL;
|
|
}
|
|
|
|
Result bufferProducerRequestBuffer(s32 bufferIdx, bufferProducerGraphicBuffer *buf)
|
|
{
|
|
Result rc;
|
|
Parcel parcel, parcel_reply;
|
|
|
|
if (g_bufferProducerBinderSession == NULL)
|
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
parcelInitialize(&parcel);
|
|
parcelInitialize(&parcel_reply);
|
|
|
|
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
|
|
parcelWriteInt32(&parcel, bufferIdx);
|
|
|
|
rc = parcelTransact(g_bufferProducerBinderSession, REQUEST_BUFFER, &parcel, &parcel_reply);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
int nonNull = parcelReadInt32(&parcel_reply);
|
|
|
|
if (nonNull != 0) {
|
|
size_t tmpsize=0;
|
|
void* tmp_ptr;
|
|
|
|
tmp_ptr = parcelReadFlattenedObject(&parcel_reply, &tmpsize);
|
|
if (tmp_ptr==NULL || tmpsize!=sizeof(bufferProducerGraphicBuffer)) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
|
if (buf) memcpy(buf, tmp_ptr, sizeof(bufferProducerGraphicBuffer));
|
|
}
|
|
|
|
int status = parcelReadInt32(&parcel_reply);
|
|
|
|
if (status != 0) {
|
|
rc = MAKERESULT(Module_Libnx, LibnxError_BufferProducerError);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result bufferProducerDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf, bufferProducerFence *fence)
|
|
{
|
|
Result rc;
|
|
Parcel parcel, parcel_reply;
|
|
|
|
if (g_bufferProducerBinderSession == NULL)
|
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
parcelInitialize(&parcel);
|
|
parcelInitialize(&parcel_reply);
|
|
|
|
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
|
|
|
|
parcelWriteInt32(&parcel, async);
|
|
parcelWriteUInt32(&parcel, width);
|
|
parcelWriteUInt32(&parcel, height);
|
|
parcelWriteInt32(&parcel, format);
|
|
parcelWriteUInt32(&parcel, usage);
|
|
|
|
rc = parcelTransact(g_bufferProducerBinderSession, DEQUEUE_BUFFER, &parcel, &parcel_reply);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
*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!=sizeof(bufferProducerFence)) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
|
if (fence) memcpy(fence, tmp_ptr, sizeof(bufferProducerFence));
|
|
}
|
|
|
|
int result = parcelReadInt32(&parcel_reply);
|
|
if (result != 0)
|
|
rc = MAKERESULT(Module_Libnx, LibnxError_BufferProducerError);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result bufferProducerDetachBuffer(s32 slot)
|
|
{
|
|
Result rc;
|
|
Parcel parcel, parcel_reply;
|
|
|
|
if (g_bufferProducerBinderSession == NULL)
|
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
parcelInitialize(&parcel);
|
|
parcelInitialize(&parcel_reply);
|
|
|
|
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
|
|
parcelWriteInt32(&parcel, slot);
|
|
|
|
rc = parcelTransact(g_bufferProducerBinderSession, DETACH_BUFFER, &parcel, &parcel_reply);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
//TODO: parse reply
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result bufferProducerQueueBuffer(s32 buf, bufferProducerQueueBufferInput *input, bufferProducerQueueBufferOutput *output)
|
|
{
|
|
Result rc;
|
|
Parcel parcel, parcel_reply;
|
|
|
|
if (g_bufferProducerBinderSession == NULL)
|
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
parcelInitialize(&parcel);
|
|
parcelInitialize(&parcel_reply);
|
|
|
|
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
|
|
parcelWriteInt32(&parcel, buf);
|
|
parcelWriteFlattenedObject(&parcel, input, sizeof(bufferProducerQueueBufferInput));
|
|
|
|
rc = parcelTransact(g_bufferProducerBinderSession, QUEUE_BUFFER, &parcel, &parcel_reply);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
if (parcelReadData(&parcel_reply, output, sizeof(bufferProducerQueueBufferOutput))==NULL) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
|
|
|
int result = parcelReadInt32(&parcel_reply);
|
|
if (result != 0)
|
|
rc = MAKERESULT(Module_Libnx, LibnxError_BufferProducerError);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result bufferProducerQuery(s32 what, s32* value)
|
|
{
|
|
Result rc;
|
|
Parcel parcel, parcel_reply;
|
|
|
|
if (g_bufferProducerBinderSession == NULL)
|
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
parcelInitialize(&parcel);
|
|
parcelInitialize(&parcel_reply);
|
|
|
|
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
|
|
parcelWriteInt32(&parcel, what);
|
|
|
|
rc = parcelTransact(g_bufferProducerBinderSession, QUERY, &parcel, &parcel_reply);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
*value = parcelReadInt32(&parcel_reply);
|
|
|
|
int result = parcelReadInt32(&parcel_reply);
|
|
if (result != 0)
|
|
rc = MAKERESULT(Module_Libnx, LibnxError_BufferProducerError);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result bufferProducerConnect(s32 api, bool producerControlledByApp, bufferProducerQueueBufferOutput *output)
|
|
{
|
|
Result rc;
|
|
Parcel parcel, parcel_reply;
|
|
|
|
if (g_bufferProducerBinderSession == NULL)
|
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
parcelInitialize(&parcel);
|
|
parcelInitialize(&parcel_reply);
|
|
|
|
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
|
|
|
|
// Hard-code this as if listener==NULL, since that's not known to be used officially.
|
|
parcelWriteInt32(&parcel, 0);
|
|
parcelWriteInt32(&parcel, api);
|
|
parcelWriteInt32(&parcel, producerControlledByApp);
|
|
|
|
rc = parcelTransact(g_bufferProducerBinderSession, CONNECT, &parcel, &parcel_reply);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
if (parcelReadData(&parcel_reply, output, sizeof(bufferProducerQueueBufferOutput))==NULL) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
|
|
|
int result = parcelReadInt32(&parcel_reply);
|
|
if (result != 0)
|
|
rc = MAKERESULT(Module_Libnx, LibnxError_BufferProducerError);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result bufferProducerDisconnect(s32 api)
|
|
{
|
|
Result rc;
|
|
Parcel parcel, parcel_reply;
|
|
|
|
if (g_bufferProducerBinderSession == NULL)
|
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
parcelInitialize(&parcel);
|
|
parcelInitialize(&parcel_reply);
|
|
|
|
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
|
|
parcelWriteInt32(&parcel, api);
|
|
|
|
rc = parcelTransact(g_bufferProducerBinderSession, DISCONNECT, &parcel, &parcel_reply);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
//TODO: parse reply
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
Result bufferProducerGraphicBufferInit(s32 buf, bufferProducerGraphicBuffer *input)
|
|
{
|
|
Result rc;
|
|
Parcel parcel, parcel_reply;
|
|
bool flag = 0;
|
|
|
|
if (g_bufferProducerBinderSession==NULL) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
parcelInitialize(&parcel);
|
|
parcelInitialize(&parcel_reply);
|
|
|
|
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
|
|
parcelWriteInt32(&parcel, buf);
|
|
|
|
if (input!=NULL) flag = 1;
|
|
parcelWriteInt32(&parcel, flag);
|
|
if (flag) parcelWriteFlattenedObject(&parcel, input, sizeof(bufferProducerGraphicBuffer));
|
|
|
|
rc = parcelTransact(g_bufferProducerBinderSession, GRAPHIC_BUFFER_INIT, &parcel, &parcel_reply);
|
|
|
|
if (R_SUCCEEDED(rc)) {
|
|
int result = parcelReadInt32(&parcel_reply);
|
|
if (result != 0)
|
|
rc = MAKERESULT(Module_Libnx, LibnxError_BufferProducerError);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|