From 97dced543e182ca3abdba8fc84bf36b12bf5044e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 29 Oct 2017 14:42:51 +0100 Subject: [PATCH] Share the conversion code between vulkan and D3D, fixing the missing format thing. --- CMakeLists.txt | 3 +- ext/native/native.vcxproj | 3 +- ext/native/native.vcxproj.filters | 5 +- ext/native/thin3d/DataFormat.h | 71 +++++++++++++++++++++++ ext/native/thin3d/VulkanQueueRunner.cpp | 58 +----------------- ext/native/thin3d/VulkanQueueRunner.h | 4 +- ext/native/thin3d/VulkanRenderManager.cpp | 2 +- ext/native/thin3d/VulkanRenderManager.h | 4 +- ext/native/thin3d/thin3d.cpp | 55 +++++++++++++++++- ext/native/thin3d/thin3d.h | 63 +------------------- ext/native/thin3d/thin3d_d3d11.cpp | 50 ---------------- ext/native/thin3d/thin3d_vulkan.cpp | 4 +- 12 files changed, 142 insertions(+), 180 deletions(-) create mode 100644 ext/native/thin3d/DataFormat.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 30acdec62a..2135eb8ba2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -808,7 +808,8 @@ if(VULKAN) ext/native/thin3d/VulkanRenderManager.cpp ext/native/thin3d/VulkanRenderManager.h ext/native/thin3d/VulkanQueueRunner.cpp - ext/native/thin3d/VulkanQueueRunner.h) + ext/native/thin3d/VulkanQueueRunner.h + ext/native/thin3d/DataFormat.h) endif() if(WIN32) set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index 681a99b453..aa3b268a19 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -240,6 +240,7 @@ + @@ -760,4 +761,4 @@ - + \ No newline at end of file diff --git a/ext/native/native.vcxproj.filters b/ext/native/native.vcxproj.filters index 57aee62de4..6996479a53 100644 --- a/ext/native/native.vcxproj.filters +++ b/ext/native/native.vcxproj.filters @@ -326,6 +326,9 @@ thin3d + + thin3d + @@ -865,4 +868,4 @@ {06c6305a-a646-485b-85b9-645a24dd6553} - + \ No newline at end of file diff --git a/ext/native/thin3d/DataFormat.h b/ext/native/thin3d/DataFormat.h new file mode 100644 index 0000000000..fa9a8325be --- /dev/null +++ b/ext/native/thin3d/DataFormat.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +namespace Draw { + +enum class DataFormat : uint8_t { + UNDEFINED, + + R8_UNORM, + R8G8_UNORM, + R8G8B8_UNORM, + + R8G8B8A8_UNORM, + R8G8B8A8_UNORM_SRGB, + B8G8R8A8_UNORM, // D3D style + B8G8R8A8_UNORM_SRGB, // D3D style + + R8G8B8A8_SNORM, + R8G8B8A8_UINT, + R8G8B8A8_SINT, + + R4G4_UNORM_PACK8, + A4R4G4B4_UNORM_PACK16, // A4 in the UPPER bit + B4G4R4A4_UNORM_PACK16, + R4G4B4A4_UNORM_PACK16, + R5G6B5_UNORM_PACK16, + B5G6R5_UNORM_PACK16, + R5G5B5A1_UNORM_PACK16, // A1 in the LOWER bit + B5G5R5A1_UNORM_PACK16, // A1 in the LOWER bit + A1R5G5B5_UNORM_PACK16, // A1 in the UPPER bit. + + R16_FLOAT, + R16G16_FLOAT, + R16G16B16A16_FLOAT, + + R32_FLOAT, + R32G32_FLOAT, + R32G32B32_FLOAT, + R32G32B32A32_FLOAT, + + // Block compression formats. + // These are modern names for DXT and friends, now patent free. + // https://msdn.microsoft.com/en-us/library/bb694531.aspx + BC1_RGBA_UNORM_BLOCK, + BC1_RGBA_SRGB_BLOCK, + BC2_UNORM_BLOCK, // 4-bit straight alpha + DXT1 color. Usually not worth using + BC2_SRGB_BLOCK, + BC3_UNORM_BLOCK, // 3-bit alpha with 2 ref values (+ magic) + DXT1 color + BC3_SRGB_BLOCK, + BC4_UNORM_BLOCK, // 1-channel, same storage as BC3 alpha + BC4_SNORM_BLOCK, + BC5_UNORM_BLOCK, // 2-channel RG, each has same storage as BC3 alpha + BC5_SNORM_BLOCK, + BC6H_UFLOAT_BLOCK, // TODO + BC6H_SFLOAT_BLOCK, + BC7_UNORM_BLOCK, // Highly advanced, very expensive to compress, very good quality. + BC7_SRGB_BLOCK, + + ETC1, + + S8, + D16, + D24_S8, + D32F, + D32F_S8, +}; + +void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format); + +} // namespace diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 734daa3ddd..f4028a0bfa 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -1,5 +1,4 @@ -#include "Common/ColorConv.h" - +#include "DataFormat.h" #include "VulkanQueueRunner.h" #include "VulkanRenderManager.h" @@ -747,60 +746,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd // NOTE: Can't read the buffer using the CPU here - need to sync first. } -// Would love to share this with D3D11 but don't have a shared format enum we can use... as we don't want -// to depend on thin3d here. -// TODO: SSE/NEON -// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :) -// Strides are in pixels. -void ConvertFromRGBA8888(u8 *dst, const u8 *src, u32 dstStride, u32 srcStride, u32 width, u32 height, VkFormat format) { - // Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP. - const u32 *src32 = (const u32 *)src; - - if (format == VK_FORMAT_R8G8B8A8_UNORM) { - u32 *dst32 = (u32 *)dst; - if (src == dst) { - return; - } else { - for (u32 y = 0; y < height; ++y) { - memcpy(dst32, src32, width * 4); - src32 += srcStride; - dst32 += dstStride; - } - } - } else { - // But here it shouldn't matter if they do intersect - u16 *dst16 = (u16 *)dst; - switch (format) { - case VK_FORMAT_B5G6R5_UNORM_PACK16: // BGR 565 - for (u32 y = 0; y < height; ++y) { - ConvertRGBA8888ToRGB565(dst16, src32, width); - src32 += srcStride; - dst16 += dstStride; - } - break; - case VK_FORMAT_A1R5G5B5_UNORM_PACK16: // ABGR 1555 - for (u32 y = 0; y < height; ++y) { - ConvertRGBA8888ToRGBA5551(dst16, src32, width); - src32 += srcStride; - dst16 += dstStride; - } - break; - case VK_FORMAT_R4G4B4A4_UNORM_PACK16: // ABGR 4444 - for (u32 y = 0; y < height; ++y) { - ConvertRGBA8888ToRGBA4444(dst16, src32, width); - src32 += srcStride; - dst16 += dstStride; - } - break; - default: - Crash(); - // Not possible. - break; - } - } -} - -void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, VkFormat destFormat, int pixelStride, uint8_t *pixels) { +void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) { // Read back to the requested address in ram from buffer. void *mappedData; const int srcPixelSize = 4; // TODO: Fix. diff --git a/ext/native/thin3d/VulkanQueueRunner.h b/ext/native/thin3d/VulkanQueueRunner.h index 477d361421..05accdf6a5 100644 --- a/ext/native/thin3d/VulkanQueueRunner.h +++ b/ext/native/thin3d/VulkanQueueRunner.h @@ -4,7 +4,7 @@ #include "Common/Vulkan/VulkanContext.h" #include "math/dataconv.h" -#include "thin3d/thin3d.h" +#include "thin3d/DataFormat.h" class VKRFramebuffer; struct VKRImage; @@ -156,7 +156,7 @@ public: return (int)depth * 3 + (int)color; } - void CopyReadbackBuffer(int width, int height, VkFormat destFormat, int pixelStride, uint8_t *pixels); + void CopyReadbackBuffer(int width, int height, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels); private: void InitBackbufferRenderPass(); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 7cf2c4bd11..e74eb71853 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -327,7 +327,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR curHeight_ = fb ? fb->height : vulkan_->GetBackbufferHeight(); } -void VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, VkFormat destFormat, uint8_t *pixels, int pixelStride) { +void VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) { VKRStep *step = new VKRStep{ VKRStepType::READBACK }; step->readback.aspectMask = aspectBits; step->readback.src = src; diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 063c37a1c0..717539cee0 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -11,7 +11,7 @@ #include "Common/Vulkan/VulkanContext.h" #include "math/dataconv.h" -#include "thin3d/thin3d.h" +#include "thin3d/DataFormat.h" #include "thin3d/VulkanQueueRunner.h" // Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine @@ -85,7 +85,7 @@ public: void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil); VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment); - void CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, VkFormat destFormat, uint8_t *pixels, int pixelStride); + void CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride); void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, int aspectMask); void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, int aspectMask, VkFilter filter); diff --git a/ext/native/thin3d/thin3d.cpp b/ext/native/thin3d/thin3d.cpp index 1de3bbba4d..39bdc447bc 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/ext/native/thin3d/thin3d.cpp @@ -1,7 +1,9 @@ #include -#include +#include #include "base/logging.h" +#include "thin3d/thin3d.h" +#include "Common/ColorConv.h" namespace Draw { @@ -320,4 +322,55 @@ DrawContext::~DrawContext() { } } +// TODO: SSE/NEON +// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :) +void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) { + // Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP. + const uint32_t *src32 = (const uint32_t *)src; + + if (format == Draw::DataFormat::R8G8B8A8_UNORM) { + uint32_t *dst32 = (uint32_t *)dst; + if (src == dst) { + return; + } else { + for (uint32_t y = 0; y < height; ++y) { + memcpy(dst32, src32, width * 4); + src32 += srcStride; + dst32 += dstStride; + } + } + } else { + // But here it shouldn't matter if they do intersect + uint16_t *dst16 = (uint16_t *)dst; + switch (format) { + case Draw::DataFormat::R5G6B5_UNORM_PACK16: // BGR 565 + for (uint32_t y = 0; y < height; ++y) { + ConvertRGBA8888ToRGB565(dst16, src32, width); + src32 += srcStride; + dst16 += dstStride; + } + break; + case Draw::DataFormat::A1R5G5B5_UNORM_PACK16: // ABGR 1555 + for (uint32_t y = 0; y < height; ++y) { + ConvertRGBA8888ToRGBA5551(dst16, src32, width); + src32 += srcStride; + dst16 += dstStride; + } + break; + case Draw::DataFormat::A4R4G4B4_UNORM_PACK16: // ABGR 4444 + for (uint32_t y = 0; y < height; ++y) { + ConvertRGBA8888ToRGBA4444(dst16, src32, width); + src32 += srcStride; + dst16 += dstStride; + } + break; + case Draw::DataFormat::R8G8B8A8_UNORM: + case Draw::DataFormat::UNDEFINED: + // Not possible. + break; + } + } +} + + } // namespace Draw diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 6b3a6dfac9..0dead1552a 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -12,6 +12,7 @@ #include #include "base/logging.h" +#include "DataFormat.h" class Matrix4x4; @@ -176,68 +177,6 @@ enum class TextureType : uint8_t { ARRAY2D, }; -enum class DataFormat : uint8_t { - UNDEFINED, - - R8_UNORM, - R8G8_UNORM, - R8G8B8_UNORM, - - R8G8B8A8_UNORM, - R8G8B8A8_UNORM_SRGB, - B8G8R8A8_UNORM, // D3D style - B8G8R8A8_UNORM_SRGB, // D3D style - - R8G8B8A8_SNORM, - R8G8B8A8_UINT, - R8G8B8A8_SINT, - - R4G4_UNORM_PACK8, - A4R4G4B4_UNORM_PACK16, // A4 in the UPPER bit - B4G4R4A4_UNORM_PACK16, - R4G4B4A4_UNORM_PACK16, - R5G6B5_UNORM_PACK16, - B5G6R5_UNORM_PACK16, - R5G5B5A1_UNORM_PACK16, // A1 in the LOWER bit - B5G5R5A1_UNORM_PACK16, // A1 in the LOWER bit - A1R5G5B5_UNORM_PACK16, // A1 in the UPPER bit. - - R16_FLOAT, - R16G16_FLOAT, - R16G16B16A16_FLOAT, - - R32_FLOAT, - R32G32_FLOAT, - R32G32B32_FLOAT, - R32G32B32A32_FLOAT, - - // Block compression formats. - // These are modern names for DXT and friends, now patent free. - // https://msdn.microsoft.com/en-us/library/bb694531.aspx - BC1_RGBA_UNORM_BLOCK, - BC1_RGBA_SRGB_BLOCK, - BC2_UNORM_BLOCK, // 4-bit straight alpha + DXT1 color. Usually not worth using - BC2_SRGB_BLOCK, - BC3_UNORM_BLOCK, // 3-bit alpha with 2 ref values (+ magic) + DXT1 color - BC3_SRGB_BLOCK, - BC4_UNORM_BLOCK, // 1-channel, same storage as BC3 alpha - BC4_SNORM_BLOCK, - BC5_UNORM_BLOCK, // 2-channel RG, each has same storage as BC3 alpha - BC5_SNORM_BLOCK, - BC6H_UFLOAT_BLOCK, // TODO - BC6H_SFLOAT_BLOCK, - BC7_UNORM_BLOCK, // Highly advanced, very expensive to compress, very good quality. - BC7_SRGB_BLOCK, - - ETC1, - - S8, - D16, - D24_S8, - D32F, - D32F_S8, -}; - enum class ShaderStage { VERTEX, FRAGMENT, diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index a40d4c4bfc..72e73fe951 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -1310,56 +1310,6 @@ bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, return false; } -// TODO: SSE/NEON -// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :) -void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 width, u32 height, Draw::DataFormat format) { - // Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP. - const u32 *src32 = (const u32 *)src; - - if (format == Draw::DataFormat::R8G8B8A8_UNORM) { - u32 *dst32 = (u32 *)dst; - if (src == dst) { - return; - } else { - for (u32 y = 0; y < height; ++y) { - memcpy(dst32, src32, width * 4); - src32 += srcStride; - dst32 += dstStride; - } - } - } else { - // But here it shouldn't matter if they do intersect - u16 *dst16 = (u16 *)dst; - switch (format) { - case Draw::DataFormat::R5G6B5_UNORM_PACK16: // BGR 565 - for (u32 y = 0; y < height; ++y) { - ConvertRGBA8888ToRGB565(dst16, src32, width); - src32 += srcStride; - dst16 += dstStride; - } - break; - case Draw::DataFormat::A1R5G5B5_UNORM_PACK16: // ABGR 1555 - for (u32 y = 0; y < height; ++y) { - ConvertRGBA8888ToRGBA5551(dst16, src32, width); - src32 += srcStride; - dst16 += dstStride; - } - break; - case Draw::DataFormat::A4R4G4B4_UNORM_PACK16: // ABGR 4444 - for (u32 y = 0; y < height; ++y) { - ConvertRGBA8888ToRGBA4444(dst16, src32, width); - src32 += srcStride; - dst16 += dstStride; - } - break; - case Draw::DataFormat::R8G8B8A8_UNORM: - case Draw::DataFormat::UNDEFINED: - // Not possible. - break; - } - } -} - bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int bx, int by, int bw, int bh, Draw::DataFormat format, void *pixels, int pixelStride) { D3D11Framebuffer *fb = (D3D11Framebuffer *)src; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index b6a8161baa..9ea34596c7 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -1288,8 +1288,6 @@ bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int sr bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride) { VKFramebuffer *src = (VKFramebuffer *)srcfb; - VkFormat vkFormat = DataFormatToVulkan(format); - int aspectMask = 0; if (channelBits & FBChannel::FB_COLOR_BIT) { aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT; @@ -1297,7 +1295,7 @@ bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits, if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - renderManager_.CopyFramebufferToMemorySync(src->GetFB(), aspectMask, x, y, w, h, vkFormat, (uint8_t *)pixels, pixelStride); + renderManager_.CopyFramebufferToMemorySync(src->GetFB(), aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride); return true; }