mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Share the conversion code between vulkan and D3D, fixing the missing format thing.
This commit is contained in:
parent
93c785b76d
commit
97dced543e
12 changed files with 142 additions and 180 deletions
|
@ -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}
|
||||
|
|
|
@ -240,6 +240,7 @@
|
|||
<ClInclude Include="gfx_es2\draw_text_qt.h" />
|
||||
<ClInclude Include="gfx_es2\draw_text_win.h" />
|
||||
<ClInclude Include="thin3d\d3d11_loader.h" />
|
||||
<ClInclude Include="thin3d\DataFormat.h" />
|
||||
<ClInclude Include="thin3d\VulkanQueueRunner.h" />
|
||||
<ClInclude Include="thin3d\VulkanRenderManager.h" />
|
||||
<ClInclude Include="util\text\wrap_text.h" />
|
||||
|
@ -760,4 +761,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -326,6 +326,9 @@
|
|||
<ClInclude Include="thin3d\VulkanRenderManager.h">
|
||||
<Filter>thin3d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="thin3d\DataFormat.h">
|
||||
<Filter>thin3d</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="gfx\gl_debug_log.cpp">
|
||||
|
@ -865,4 +868,4 @@
|
|||
<UniqueIdentifier>{06c6305a-a646-485b-85b9-645a24dd6553}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
71
ext/native/thin3d/DataFormat.h
Normal file
71
ext/native/thin3d/DataFormat.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include <cstring>
|
||||
#include <thin3d/thin3d.h>
|
||||
#include <cstdint>
|
||||
|
||||
#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
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <string>
|
||||
|
||||
#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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue