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;
}