libnx/nx/source/gfx/buffer_producer.c

253 lines
6.6 KiB
C

#include <string.h>
#include <switch.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 */ TEGRA_BUFFER_INIT, // Custom Switch-specific command - unofficial name.
};
static char g_bufferProducer_InterfaceDescriptor[] = "android.gui.IGraphicBufferProducer";
static binderSession *g_bufferProducerBinderSession;
Result bufferProducerInitialize(binderSession *session)
{
g_bufferProducerBinderSession = session;
return 0;
}
void bufferProducerExit()
{
g_bufferProducerBinderSession = NULL;
}
Result bufferProducerRequestBuffer(s32 bufferIdx)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bufferProducerBinderSession == NULL)
return MAKERESULT(MODULE_LIBNX, LIBNX_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) {
// Fixme
fatalSimple(222 | (100 << 9));
}
int status = parcelReadInt32(&parcel_reply);
if (status != 0) {
rc = MAKERESULT(MODULE_LIBNX, LIBNX_BUFFERPRODUCER_ERROR);
}
*/
}
return rc;
}
Result bufferProducerDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage, s32 *buf)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bufferProducerBinderSession == NULL)
return MAKERESULT(MODULE_LIBNX, LIBNX_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)) {
// TODO: parse reply
*buf = parcelReadInt32(&parcel_reply);
}
return rc;
}
Result bufferProducerDetachBuffer(s32 slot)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bufferProducerBinderSession == NULL)
return MAKERESULT(MODULE_LIBNX, LIBNX_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, u8 input[0x5c])
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bufferProducerBinderSession == NULL)
return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
parcelInitialize(&parcel);
parcelInitialize(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
parcelWriteInt32(&parcel, buf);
parcelWriteData(&parcel, input, 0x5c);
rc = parcelTransact(g_bufferProducerBinderSession, QUEUE_BUFFER, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) {
//TODO: parse reply
}
return rc;
}
Result bufferProducerQuery(s32 what, s32* value)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bufferProducerBinderSession == NULL)
return MAKERESULT(MODULE_LIBNX, LIBNX_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, LIBNX_BUFFERPRODUCER_ERROR);
}
return rc;
}
Result bufferProducerConnect(s32 api, bool producerControlledByApp)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bufferProducerBinderSession == NULL)
return MAKERESULT(MODULE_LIBNX, LIBNX_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)) {
//TODO: parse reply (contains 32bit width and height)
}
return rc;
}
Result bufferProducerDisconnect(s32 api)
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bufferProducerBinderSession == NULL)
return MAKERESULT(MODULE_LIBNX, LIBNX_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 bufferProducerTegraBufferInit(s32 buf, u8 input[0x178])
{
Result rc;
Parcel parcel, parcel_reply;
if (g_bufferProducerBinderSession==NULL) return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
parcelInitialize(&parcel);
parcelInitialize(&parcel_reply);
parcelWriteInterfaceToken(&parcel, g_bufferProducer_InterfaceDescriptor);
parcelWriteInt32(&parcel, buf);
parcelWriteData(&parcel, input, 0x178);
rc = parcelTransact(g_bufferProducerBinderSession, TEGRA_BUFFER_INIT, &parcel, &parcel_reply);
if (R_SUCCEEDED(rc)) {
// TODO: parse reply
}
return 0;
}