mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-26 16:24:17 +01:00
Fix GraphicBufferProducer
Format Bug
The format provided in `GraphicBuffer` can be misleading and is supplied as `None` by the Deko3D Swapchain, it instead supplies the real format in the `NvGraphicHandle` which we now utilize instead of the one in `GraphicBuffer`.
This commit is contained in:
parent
18cf0b82d6
commit
bc378ad135
@ -138,8 +138,9 @@ namespace skyline::service::hosbinder {
|
|||||||
// All buffers must be preallocated on the client application and attached to an Android buffer using SetPreallocatedBuffer
|
// All buffers must be preallocated on the client application and attached to an Android buffer using SetPreallocatedBuffer
|
||||||
return AndroidStatus::NoMemory;
|
return AndroidStatus::NoMemory;
|
||||||
}
|
}
|
||||||
auto &surface{buffer->graphicBuffer->graphicHandle.surfaces.front()};
|
auto &handle{buffer->graphicBuffer->graphicHandle};
|
||||||
if (buffer->graphicBuffer->format != format || surface.width != width || surface.height != height || (buffer->graphicBuffer->usage & usage) != usage) {
|
auto &surface{handle.surfaces.front()};
|
||||||
|
if (handle.format != format || surface.width != width || surface.height != height || (buffer->graphicBuffer->usage & usage) != usage) {
|
||||||
state.logger->Warn("Buffer which has been dequeued isn't compatible with the supplied parameters: Dimensions: {}x{}={}x{}, Format: {}={}, Usage: 0x{:X}=0x{:X}", width, height, surface.width, surface.height, ToString(format), ToString(buffer->graphicBuffer->format), usage, buffer->graphicBuffer->usage);
|
state.logger->Warn("Buffer which has been dequeued isn't compatible with the supplied parameters: Dimensions: {}x{}={}x{}, Format: {}={}, Usage: 0x{:X}=0x{:X}", width, height, surface.width, surface.height, ToString(format), ToString(buffer->graphicBuffer->format), usage, buffer->graphicBuffer->usage);
|
||||||
// Nintendo doesn't deallocate the slot which was picked in here and reallocate it as a compatible buffer
|
// Nintendo doesn't deallocate the slot which was picked in here and reallocate it as a compatible buffer
|
||||||
// This is related to the comment above, Nintendo only allocates buffers on the client side
|
// This is related to the comment above, Nintendo only allocates buffers on the client side
|
||||||
@ -264,7 +265,7 @@ namespace skyline::service::hosbinder {
|
|||||||
preallocatedBufferCount = std::count_if(queue.begin(), queue.end(), [](const BufferSlot &slot) { return slot.graphicBuffer && slot.isPreallocated; });
|
preallocatedBufferCount = std::count_if(queue.begin(), queue.end(), [](const BufferSlot &slot) { return slot.graphicBuffer && slot.isPreallocated; });
|
||||||
activeSlotCount = std::count_if(queue.begin(), queue.end(), [](const BufferSlot &slot) { return slot.graphicBuffer != nullptr; });
|
activeSlotCount = std::count_if(queue.begin(), queue.end(), [](const BufferSlot &slot) { return slot.graphicBuffer != nullptr; });
|
||||||
|
|
||||||
state.logger->Debug("#{} - Dimensions: {}x{} [Stride: {}], Format: {}, Layout: {}, {}: {}, Usage: 0x{:X}, NvMap {}: {}, Buffer Start/End: 0x{:X} -> 0x{:X}", slot, surface.width, surface.height, handle.stride, ToString(graphicBuffer.format), ToString(surface.layout), surface.layout == NvSurfaceLayout::Blocklinear ? "Block Height" : "Pitch", surface.layout == NvSurfaceLayout::Blocklinear ? 1U << surface.blockHeightLog2 : surface.pitch, graphicBuffer.usage, surface.nvmapHandle ? "Handle" : "ID", surface.nvmapHandle ? surface.nvmapHandle : handle.nvmapId, surface.offset, surface.offset + surface.size);
|
state.logger->Debug("#{} - Dimensions: {}x{} [Stride: {}], Format: {}, Layout: {}, {}: {}, Usage: 0x{:X}, NvMap {}: {}, Buffer Start/End: 0x{:X} -> 0x{:X}", slot, surface.width, surface.height, handle.stride, ToString(handle.format), ToString(surface.layout), surface.layout == NvSurfaceLayout::Blocklinear ? "Block Height" : "Pitch", surface.layout == NvSurfaceLayout::Blocklinear ? 1U << surface.blockHeightLog2 : surface.pitch, graphicBuffer.usage, surface.nvmapHandle ? "Handle" : "ID", surface.nvmapHandle ? surface.nvmapHandle : handle.nvmapId, surface.offset, surface.offset + surface.size);
|
||||||
return AndroidStatus::Ok;
|
return AndroidStatus::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,8 +306,17 @@ namespace skyline::service::hosbinder {
|
|||||||
if (!buffer.texture) [[unlikely]] {
|
if (!buffer.texture) [[unlikely]] {
|
||||||
// We lazily create a texture if one isn't present at queue time, this allows us to look up the texture in the texture cache
|
// We lazily create a texture if one isn't present at queue time, this allows us to look up the texture in the texture cache
|
||||||
// If we deterministically know that the texture is written by the CPU then we can allocate a CPU-shared host texture for fast uploads
|
// If we deterministically know that the texture is written by the CPU then we can allocate a CPU-shared host texture for fast uploads
|
||||||
|
|
||||||
|
auto &handle{graphicBuffer.graphicHandle};
|
||||||
|
if (handle.magic != NvGraphicHandle::Magic)
|
||||||
|
throw exception("Unexpected NvGraphicHandle magic: {}", handle.surfaceCount);
|
||||||
|
else if (handle.surfaceCount < 1)
|
||||||
|
throw exception("At least one surface is required in a buffer: {}", handle.surfaceCount);
|
||||||
|
else if (handle.surfaceCount > 1)
|
||||||
|
throw exception("Multi-planar surfaces are not supported: {}", handle.surfaceCount);
|
||||||
|
|
||||||
gpu::texture::Format format;
|
gpu::texture::Format format;
|
||||||
switch (graphicBuffer.format) {
|
switch (handle.format) {
|
||||||
case AndroidPixelFormat::RGBA8888:
|
case AndroidPixelFormat::RGBA8888:
|
||||||
case AndroidPixelFormat::RGBX8888:
|
case AndroidPixelFormat::RGBX8888:
|
||||||
format = gpu::format::RGBA8888Unorm;
|
format = gpu::format::RGBA8888Unorm;
|
||||||
@ -317,17 +327,9 @@ namespace skyline::service::hosbinder {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw exception("Unknown format in buffer: '{}' ({})", ToString(graphicBuffer.format), static_cast<u32>(graphicBuffer.format));
|
throw exception("Unknown format in buffer: '{}' ({})", ToString(handle.format), static_cast<u32>(handle.format));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &handle{graphicBuffer.graphicHandle};
|
|
||||||
if (handle.magic != NvGraphicHandle::Magic)
|
|
||||||
throw exception("Unexpected NvGraphicHandle magic: {}", handle.surfaceCount);
|
|
||||||
else if (handle.surfaceCount < 1)
|
|
||||||
throw exception("At least one surface is required in a buffer: {}", handle.surfaceCount);
|
|
||||||
else if (handle.surfaceCount > 1)
|
|
||||||
throw exception("Multi-planar surfaces are not supported: {}", handle.surfaceCount);
|
|
||||||
|
|
||||||
auto &surface{graphicBuffer.graphicHandle.surfaces.at(0)};
|
auto &surface{graphicBuffer.graphicHandle.surfaces.at(0)};
|
||||||
if (surface.scanFormat != NvDisplayScanFormat::Progressive)
|
if (surface.scanFormat != NvDisplayScanFormat::Progressive)
|
||||||
throw exception("Non-Progressive surfaces are not supported: {}", ToString(surface.scanFormat));
|
throw exception("Non-Progressive surfaces are not supported: {}", ToString(surface.scanFormat));
|
||||||
@ -595,7 +597,7 @@ namespace skyline::service::hosbinder {
|
|||||||
else if (surface.layout == NvSurfaceLayout::Tiled)
|
else if (surface.layout == NvSurfaceLayout::Tiled)
|
||||||
throw exception("Legacy 16Bx16 tiled surfaces are not supported");
|
throw exception("Legacy 16Bx16 tiled surfaces are not supported");
|
||||||
|
|
||||||
state.logger->Debug("#{} - Dimensions: {}x{} [Stride: {}], Format: {}, Layout: {}, {}: {}, Usage: 0x{:X}, NvMap {}: {}, Buffer Start/End: 0x{:X} -> 0x{:X}", slot, surface.width, surface.height, handle.stride, ToString(graphicBuffer->format), ToString(surface.layout), surface.layout == NvSurfaceLayout::Blocklinear ? "Block Height" : "Pitch", surface.layout == NvSurfaceLayout::Blocklinear ? 1U << surface.blockHeightLog2 : surface.pitch, graphicBuffer->usage, surface.nvmapHandle ? "Handle" : "ID", surface.nvmapHandle ? surface.nvmapHandle : handle.nvmapId, surface.offset, surface.offset + surface.size);
|
state.logger->Debug("#{} - Dimensions: {}x{} [Stride: {}], Format: {}, Layout: {}, {}: {}, Usage: 0x{:X}, NvMap {}: {}, Buffer Start/End: 0x{:X} -> 0x{:X}", slot, surface.width, surface.height, handle.stride, ToString(handle.format), ToString(surface.layout), surface.layout == NvSurfaceLayout::Blocklinear ? "Block Height" : "Pitch", surface.layout == NvSurfaceLayout::Blocklinear ? 1U << surface.blockHeightLog2 : surface.pitch, graphicBuffer->usage, surface.nvmapHandle ? "Handle" : "ID", surface.nvmapHandle ? surface.nvmapHandle : handle.nvmapId, surface.offset, surface.offset + surface.size);
|
||||||
} else {
|
} else {
|
||||||
state.logger->Debug("#{} - No GraphicBuffer", slot);
|
state.logger->Debug("#{} - No GraphicBuffer", slot);
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ namespace skyline::service::hosbinder {
|
|||||||
static_assert(sizeof(NvSurface) == 0x58);
|
static_assert(sizeof(NvSurface) == 0x58);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The integers of the native_handle used by Nvidia to marshall the surfaces in this buffer
|
* @brief The format of the native_handle integers used by Nvidia to marshall the surface metadata of the GraphicBuffer
|
||||||
*/
|
*/
|
||||||
struct NvGraphicHandle {
|
struct NvGraphicHandle {
|
||||||
constexpr static u32 Magic{0xDAFFCAFF};
|
constexpr static u32 Magic{0xDAFFCAFF};
|
||||||
@ -199,7 +199,7 @@ namespace skyline::service::hosbinder {
|
|||||||
u32 ownerPid; //!< Same as the upper 32-bits of the ID in the GraphicBuffer (0x2F)
|
u32 ownerPid; //!< Same as the upper 32-bits of the ID in the GraphicBuffer (0x2F)
|
||||||
u32 type;
|
u32 type;
|
||||||
u32 usage; //!< The Gralloc usage flags, same as GraphicBuffer
|
u32 usage; //!< The Gralloc usage flags, same as GraphicBuffer
|
||||||
u32 format; //!< The internal format of the buffer
|
AndroidPixelFormat format; //!< The internal format of the buffer
|
||||||
u32 externalFormat; //!< The external format that's exposed by Gralloc
|
u32 externalFormat; //!< The external format that's exposed by Gralloc
|
||||||
u32 stride;
|
u32 stride;
|
||||||
u32 size; //!< The size of the buffer in bytes
|
u32 size; //!< The size of the buffer in bytes
|
||||||
@ -213,6 +213,7 @@ namespace skyline::service::hosbinder {
|
|||||||
/**
|
/**
|
||||||
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/GraphicBuffer.h
|
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/GraphicBuffer.h
|
||||||
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/ui/GraphicBuffer.cpp;l=266-301
|
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/ui/GraphicBuffer.cpp;l=266-301
|
||||||
|
* @note None of the values from here should really be used aside from Gralloc usage, the ones in NvGraphicHandle take precedence
|
||||||
*/
|
*/
|
||||||
struct GraphicBuffer {
|
struct GraphicBuffer {
|
||||||
constexpr static u32 Magic{'GBFR'}; //!< The magic is in little-endian, we do not need to use 'util::MakeMagic'
|
constexpr static u32 Magic{'GBFR'}; //!< The magic is in little-endian, we do not need to use 'util::MakeMagic'
|
||||||
|
Loading…
Reference in New Issue
Block a user