From 68c990c0419a3b6167388c666f42256e94cbe81e Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Wed, 8 Dec 2021 00:42:54 +0530 Subject: [PATCH] Implement Maxwell3D Depth/Stencil Render Target Support the Maxwell3D Depth RT for Z-buffering, this just creates an equivalent `RenderTarget` object with no support on the API-user side (IE: `Draw` and `ClearBuffers`). --- .../gpu/interconnect/graphics_context.h | 61 ++++++++++++++++++- app/src/main/cpp/skyline/gpu/texture/format.h | 4 ++ .../skyline/soc/gm20b/engines/maxwell/types.h | 14 +++++ .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 28 +++++++++ .../skyline/soc/gm20b/engines/maxwell_3d.h | 11 ++++ 5 files changed, 115 insertions(+), 3 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index 1615ba55..0fcc2604 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -91,7 +91,13 @@ namespace skyline::gpu::interconnect { std::array colorRenderTargets{}; //!< The target textures to render into as color attachments maxwell3d::RenderTargetControl renderTargetControl{}; + RenderTarget depthRenderTarget{}; //!< The target texture to render depth/stencil into + public: + void SetDepthRenderTargetEnabled(bool enabled) { + depthRenderTarget.disabled = !enabled; + } + void SetRenderTargetAddressHigh(RenderTarget &renderTarget, u32 high) { renderTarget.iova.high = high; renderTarget.guest.mappings.clear(); @@ -102,6 +108,10 @@ namespace skyline::gpu::interconnect { SetRenderTargetAddressHigh(colorRenderTargets.at(index), high); } + void SetDepthRenderTargetAddressHigh(u32 high) { + SetRenderTargetAddressHigh(depthRenderTarget, high); + } + void SetRenderTargetAddressLow(RenderTarget &renderTarget, u32 low) { renderTarget.iova.low = low; renderTarget.guest.mappings.clear(); @@ -112,6 +122,10 @@ namespace skyline::gpu::interconnect { SetRenderTargetAddressLow(colorRenderTargets.at(index), low); } + void SetDepthRenderTargetAddressLow(u32 low) { + SetRenderTargetAddressLow(depthRenderTarget, low); + } + void SetRenderTargetWidth(RenderTarget &renderTarget, u32 value) { renderTarget.widthBytes = value; if (renderTarget.guest.tileConfig.mode == texture::TileMode::Linear && renderTarget.guest.format) @@ -124,6 +138,10 @@ namespace skyline::gpu::interconnect { SetRenderTargetWidth(colorRenderTargets.at(index), value); } + void SetDepthRenderTargetWidth(u32 value) { + SetRenderTargetWidth(depthRenderTarget, value); + } + void SetRenderTargetHeight(RenderTarget &renderTarget, u32 value) { renderTarget.guest.dimensions.height = value; renderTarget.view.reset(); @@ -133,6 +151,10 @@ namespace skyline::gpu::interconnect { SetRenderTargetHeight(colorRenderTargets.at(index), value); } + void SetDepthRenderTargetHeight(u32 value) { + SetRenderTargetHeight(depthRenderTarget, value); + } + void SetColorRenderTargetFormat(size_t index, maxwell3d::ColorRenderTarget::Format format) { auto &renderTarget{colorRenderTargets.at(index)}; renderTarget.guest.format = [&]() -> texture::Format { @@ -206,6 +228,23 @@ namespace skyline::gpu::interconnect { renderTarget.view.reset(); } + void SetDepthRenderTargetFormat(maxwell3d::DepthRtFormat format) { + depthRenderTarget.guest.format = [&]() -> texture::Format { + using MaxwellDepthRtFormat = maxwell3d::DepthRtFormat; + switch (format) { + case MaxwellDepthRtFormat::S8D24Unorm: + return format::S8D24Unorm; + default: + throw exception("Cannot translate the supplied depth RT format: 0x{:X}", static_cast(format)); + } + }(); + + if (depthRenderTarget.guest.tileConfig.mode == texture::TileMode::Linear && depthRenderTarget.guest.format) + depthRenderTarget.guest.dimensions.width = depthRenderTarget.widthBytes / depthRenderTarget.guest.format->bpb; + + depthRenderTarget.view.reset(); + } + void SetRenderTargetTileMode(RenderTarget &renderTarget, maxwell3d::RenderTargetTileMode mode) { auto &config{renderTarget.guest.tileConfig}; if (mode.isLinear) { @@ -233,17 +272,25 @@ namespace skyline::gpu::interconnect { SetRenderTargetTileMode(colorRenderTargets.at(index), mode); } + void SetDepthRenderTargetTileMode(maxwell3d::RenderTargetTileMode mode) { + SetRenderTargetTileMode(depthRenderTarget, mode); + } + void SetRenderTargetArrayMode(RenderTarget &renderTarget, maxwell3d::RenderTargetArrayMode mode) { renderTarget.guest.layerCount = mode.layerCount; - if (mode.volume) - throw exception("RT Array Volumes are not supported (with layer count = {})", mode.layerCount); renderTarget.view.reset(); } void SetColorRenderTargetArrayMode(size_t index, maxwell3d::RenderTargetArrayMode mode) { + if (mode.volume) + throw exception("Color RT Array Volumes are not supported (with layer count = {})", mode.layerCount); SetRenderTargetArrayMode(colorRenderTargets.at(index), mode); } + void SetDepthRenderTargetArrayMode(maxwell3d::RenderTargetArrayMode mode) { + SetRenderTargetArrayMode(depthRenderTarget, mode); + } + void SetRenderTargetLayerStride(RenderTarget &renderTarget, u32 layerStrideLsr2) { renderTarget.guest.layerStride = layerStrideLsr2 << 2; renderTarget.view.reset(); @@ -253,6 +300,10 @@ namespace skyline::gpu::interconnect { SetRenderTargetLayerStride(colorRenderTargets.at(index), layerStrideLsr2); } + void SetDepthRenderTargetLayerStride(u32 layerStrideLsr2) { + SetRenderTargetLayerStride(depthRenderTarget, layerStrideLsr2); + } + void SetColorRenderTargetBaseLayer(size_t index, u32 baseArrayLayer) { auto &renderTarget{colorRenderTargets.at(index)}; if (baseArrayLayer > std::numeric_limits::max()) @@ -262,7 +313,7 @@ namespace skyline::gpu::interconnect { renderTarget.view.reset(); } - TextureView *GetRenderTarget(RenderTarget& renderTarget) { + TextureView *GetRenderTarget(RenderTarget &renderTarget) { if (renderTarget.disabled) return nullptr; else if (renderTarget.view) @@ -284,6 +335,10 @@ namespace skyline::gpu::interconnect { return GetRenderTarget(colorRenderTargets.at(index)); } + TextureView *GetDepthRenderTarget() { + return GetRenderTarget(depthRenderTarget); + } + void UpdateRenderTargetControl(maxwell3d::RenderTargetControl control) { renderTargetControl = control; } diff --git a/app/src/main/cpp/skyline/gpu/texture/format.h b/app/src/main/cpp/skyline/gpu/texture/format.h index 1084cb87..6726efb9 100644 --- a/app/src/main/cpp/skyline/gpu/texture/format.h +++ b/app/src/main/cpp/skyline/gpu/texture/format.h @@ -11,6 +11,7 @@ namespace skyline::gpu::format { using vka = vk::ImageAspectFlagBits; using swc = gpu::texture::SwizzleChannel; + // Color Formats constexpr Format R8G8B8A8Unorm{sizeof(u32), vkf::eR8G8B8A8Unorm}; constexpr Format R5G6B5Unorm{sizeof(u16), vkf::eR5G6B5UnormPack16}; constexpr Format A2B10G10R10Unorm{sizeof(u32), vkf::eA2B10G10R10UnormPack32}; @@ -42,4 +43,7 @@ namespace skyline::gpu::format { constexpr Format R16G16B16A16Float{sizeof(u16) * 4, vkf::eR16G16B16A16Sfloat}; constexpr Format B8G8R8A8Unorm{sizeof(u32), vkf::eB8G8R8A8Unorm}; constexpr Format B8G8R8A8Srgb{sizeof(u32), vkf::eB8G8R8A8Srgb}; + + // Depth/Stencil Formats + constexpr Format S8D24Unorm{sizeof(u32), vkf::eD24UnormS8Uint, vka::eStencil | vka::eDepth}; // TODO: Swizzle Depth/Stencil } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h index 28eae46a..956993f2 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h @@ -108,6 +108,20 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { }; static_assert(sizeof(ColorRenderTarget) == (0x10 * sizeof(u32))); + enum class DepthRtFormat : u32 { + D32Float = 0x0A, + D16Unorm = 0x13, + S8D24Unorm = 0x14, + D24X8Unorm = 0x15, + D24S8Unorm = 0x16, + S8Uint = 0x17, + D24C8Unorm = 0x18, + D32S8X24Float = 0x19, + D24X8S8C8X16Unorm = 0x1D, + D32X8C8X16Float = 0x1E, + D32S8C8X16Float = 0x1F, + }; + constexpr static size_t ViewportCount{16}; //!< Amount of viewports on Maxwell 3D, array size for any per-viewport parameter such as transform, scissors, etc /** diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index d3234066..cd7f402e 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -115,6 +115,34 @@ namespace skyline::soc::gm20b::engine::maxwell3d { static_assert(type::RenderTargetCount == 8 && type::RenderTargetCount < BOOST_PP_LIMIT_REPEAT); #undef RENDER_TARGET_ARRAY + MAXWELL3D_CASE(depthTargetEnable, { + context.SetDepthRenderTargetEnabled(depthTargetEnable); + }) + MAXWELL3D_STRUCT_CASE(depthTargetAddress, high, { + context.SetDepthRenderTargetAddressHigh(high); + }) + MAXWELL3D_STRUCT_CASE(depthTargetAddress, low, { + context.SetDepthRenderTargetAddressLow(low); + }) + MAXWELL3D_CASE(depthTargetFormat, { + context.SetDepthRenderTargetFormat(depthTargetFormat); + }) + MAXWELL3D_CASE(depthTargetTileMode, { + context.SetDepthRenderTargetTileMode(depthTargetTileMode); + }) + MAXWELL3D_CASE(depthTargetLayerStride, { + context.SetDepthRenderTargetLayerStride(depthTargetLayerStride); + }) + MAXWELL3D_CASE(depthTargetWidth, { + context.SetDepthRenderTargetWidth(depthTargetWidth); + }) + MAXWELL3D_CASE(depthTargetHeight, { + context.SetDepthRenderTargetHeight(depthTargetHeight); + }) + MAXWELL3D_CASE(depthTargetArrayMode, { + context.SetDepthRenderTargetArrayMode(depthTargetArrayMode); + }) + #define VIEWPORT_TRANSFORM_CALLBACKS(z, index, data) \ MAXWELL3D_ARRAY_STRUCT_CASE(viewportTransforms, index, scaleX, { \ context.SetViewportX(index, scaleX, registers.viewportTransforms[index].translateX); \ diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 39c4d082..1031561d 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -109,8 +109,19 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x3E4, u32> commonColorWriteMask; //!< If enabled, the color write masks for all RTs must be set to that of the first RT Register<0x3EB, u32> rtSeparateFragData; + + Register<0x3F8, type::Address> depthTargetAddress; + Register<0x3FA, type::DepthRtFormat> depthTargetFormat; + Register<0x3FB, type::RenderTargetTileMode> depthTargetTileMode; + Register<0x3FC, u32> depthTargetLayerStride; + Register<0x458, std::array> vertexAttributeState; Register<0x487, type::RenderTargetControl> renderTargetControl; + + Register<0x48A, u32> depthTargetWidth; + Register<0x48B, u32> depthTargetHeight; + Register<0x48C, type::RenderTargetArrayMode> depthTargetArrayMode; + Register<0x4B9, u32> independentBlendEnable; Register<0x4BB, u32> alphaTestEnable; Register<0x4C3, type::CompareOp> depthTestFunc;