Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/thin3d.cpp
3187 views
1
#include <cassert>
2
#include <cstring>
3
#include <cstdint>
4
5
#include "Common/Data/Convert/ColorConv.h"
6
#include "Common/GPU/thin3d.h"
7
#include "Common/Log.h"
8
#include "Common/System/Display.h"
9
10
namespace Draw {
11
12
size_t DataFormatSizeInBytes(DataFormat fmt) {
13
switch (fmt) {
14
case DataFormat::R8_UNORM: return 1;
15
case DataFormat::R8G8_UNORM: return 2;
16
case DataFormat::R8G8B8_UNORM: return 3;
17
18
case DataFormat::R4G4_UNORM_PACK8: return 1;
19
case DataFormat::R4G4B4A4_UNORM_PACK16: return 2;
20
case DataFormat::B4G4R4A4_UNORM_PACK16: return 2;
21
case DataFormat::A4R4G4B4_UNORM_PACK16: return 2;
22
case DataFormat::R5G5B5A1_UNORM_PACK16: return 2;
23
case DataFormat::B5G5R5A1_UNORM_PACK16: return 2;
24
case DataFormat::R5G6B5_UNORM_PACK16: return 2;
25
case DataFormat::B5G6R5_UNORM_PACK16: return 2;
26
case DataFormat::A1R5G5B5_UNORM_PACK16: return 2;
27
28
case DataFormat::R8G8B8A8_UNORM:
29
case DataFormat::R8G8B8A8_UNORM_SRGB: return 4;
30
case DataFormat::B8G8R8A8_UNORM:
31
case DataFormat::B8G8R8A8_UNORM_SRGB: return 4;
32
33
case DataFormat::R8G8B8A8_SNORM: return 4;
34
case DataFormat::R8G8B8A8_UINT: return 4;
35
case DataFormat::R8G8B8A8_SINT: return 4;
36
37
case DataFormat::R16_UNORM: return 2;
38
39
case DataFormat::R16_FLOAT: return 2;
40
case DataFormat::R16G16_FLOAT: return 4;
41
case DataFormat::R16G16B16A16_FLOAT: return 8;
42
case DataFormat::R32_FLOAT: return 4;
43
case DataFormat::R32G32_FLOAT: return 8;
44
case DataFormat::R32G32B32_FLOAT: return 12;
45
case DataFormat::R32G32B32A32_FLOAT: return 16;
46
47
case DataFormat::S8: return 1;
48
case DataFormat::D16: return 2;
49
case DataFormat::D16_S8: return 3;
50
case DataFormat::D24_S8: return 4;
51
case DataFormat::D32F: return 4;
52
// Or maybe 8...
53
case DataFormat::D32F_S8: return 5;
54
55
default:
56
return 0;
57
}
58
}
59
60
const char *DataFormatToString(DataFormat fmt) {
61
switch (fmt) {
62
case DataFormat::R8_UNORM: return "R8_UNORM";
63
case DataFormat::R8G8_UNORM: return "R8G8_UNORM";
64
case DataFormat::R8G8B8A8_UNORM: return "R8G8B8A8_UNORM";
65
case DataFormat::B8G8R8A8_UNORM: return "B8G8R8A8_UNORM";
66
case DataFormat::R16_UNORM: return "R16_UNORM";
67
case DataFormat::R16_FLOAT: return "R16_FLOAT";
68
case DataFormat::R32_FLOAT: return "R32_FLOAT";
69
70
case DataFormat::S8: return "S8";
71
case DataFormat::D16: return "D16";
72
case DataFormat::D16_S8: return "D16_S8";
73
case DataFormat::D24_S8: return "D24_S8";
74
case DataFormat::D32F: return "D32F";
75
case DataFormat::D32F_S8: return "D32F_S8";
76
77
default:
78
return "(N/A)";
79
}
80
}
81
82
bool DataFormatIsDepthStencil(DataFormat fmt) {
83
switch (fmt) {
84
case DataFormat::D16:
85
case DataFormat::D16_S8:
86
case DataFormat::D24_S8:
87
case DataFormat::S8:
88
case DataFormat::D32F:
89
case DataFormat::D32F_S8:
90
return true;
91
default:
92
return false;
93
}
94
}
95
96
// We don't bother listing the formats that are irrelevant for PPSSPP, like BC6 (HDR format)
97
// or weird-shaped ASTC formats. We only support 4x4 block size formats for now.
98
// If you pass in a blockSize parameter, it receives byte count that a 4x4 block takes in this format.
99
bool DataFormatIsBlockCompressed(DataFormat fmt, int *blockSize) {
100
switch (fmt) {
101
case DataFormat::BC1_RGBA_UNORM_BLOCK:
102
case DataFormat::BC4_UNORM_BLOCK:
103
case DataFormat::ETC2_R8G8B8_UNORM_BLOCK:
104
if (blockSize) *blockSize = 8; // 64 bits
105
return true;
106
case DataFormat::BC2_UNORM_BLOCK:
107
case DataFormat::BC3_UNORM_BLOCK:
108
case DataFormat::BC5_UNORM_BLOCK:
109
case DataFormat::BC7_UNORM_BLOCK:
110
case DataFormat::ETC2_R8G8B8A1_UNORM_BLOCK:
111
case DataFormat::ETC2_R8G8B8A8_UNORM_BLOCK:
112
case DataFormat::ASTC_4x4_UNORM_BLOCK:
113
if (blockSize) *blockSize = 16; // 128 bits
114
return true;
115
default:
116
if (blockSize) *blockSize = 0;
117
return false;
118
}
119
}
120
121
int DataFormatNumChannels(DataFormat fmt) {
122
switch (fmt) {
123
case DataFormat::D16:
124
case DataFormat::D32F:
125
case DataFormat::R8_UNORM:
126
case DataFormat::R16_UNORM:
127
case DataFormat::R16_FLOAT:
128
case DataFormat::R32_FLOAT:
129
return 1;
130
case DataFormat::R8G8B8A8_UNORM:
131
case DataFormat::R8G8B8A8_UNORM_SRGB:
132
case DataFormat::B8G8R8A8_UNORM:
133
case DataFormat::B8G8R8A8_UNORM_SRGB:
134
return 4;
135
default:
136
return 0;
137
}
138
}
139
140
RefCountedObject::~RefCountedObject() {
141
const int rc = refcount_.load();
142
_dbg_assert_msg_(rc == 0xDEDEDE, "Unexpected refcount %d in object of type '%s'", rc, name_);
143
}
144
145
bool RefCountedObject::Release() {
146
if (refcount_ > 0 && refcount_ < 10000) {
147
if (--refcount_ == 0) {
148
// Make it very obvious if we try to free this again.
149
refcount_ = 0xDEDEDE;
150
delete this;
151
return true;
152
}
153
} else {
154
// No point in printing the name here if the object has already been free-d, it'll be corrupt and dangerous to print.
155
_dbg_assert_msg_(false, "Refcount (%d) invalid for object %p - corrupt?", refcount_.load(), this);
156
}
157
return false;
158
}
159
160
bool RefCountedObject::ReleaseAssertLast() {
161
bool released = Release();
162
_dbg_assert_msg_(released, "RefCountedObject: Expected to be the last reference, but isn't! (%s)", name_);
163
return released;
164
}
165
166
// ================================== PIXEL/FRAGMENT SHADERS
167
168
// The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL.
169
170
static const std::vector<ShaderSource> fsTexCol = {
171
{ShaderLanguage::GLSL_1xx,
172
"#ifdef GL_ES\n"
173
"precision lowp float;\n"
174
"#endif\n"
175
"#if __VERSION__ >= 130\n"
176
"#define varying in\n"
177
"#define texture2D texture\n"
178
"#define gl_FragColor fragColor0\n"
179
"out vec4 fragColor0;\n"
180
"#endif\n"
181
"varying vec4 oColor0;\n"
182
"varying vec2 oTexCoord0;\n"
183
"uniform sampler2D Sampler0;\n"
184
"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0) * oColor0; }\n"
185
},
186
{ShaderLanguage::HLSL_D3D11,
187
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
188
"SamplerState samp : register(s0);\n"
189
"Texture2D<float4> tex : register(t0);\n"
190
"float4 main(PS_INPUT input) : SV_Target {\n"
191
" float4 col = input.color * tex.Sample(samp, input.uv);\n"
192
" return col;\n"
193
"}\n"
194
},
195
{ShaderLanguage::GLSL_VULKAN,
196
"#version 140\n"
197
"#extension GL_ARB_separate_shader_objects : enable\n"
198
"#extension GL_ARB_shading_language_420pack : enable\n"
199
"layout(location = 0) in vec4 oColor0;\n"
200
"layout(location = 1) in vec2 oTexCoord0;\n"
201
"layout(location = 0) out vec4 fragColor0;\n"
202
"layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n"
203
"void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n"
204
}
205
};
206
207
static const std::vector<ShaderSource> fsTexColRBSwizzle = {
208
{GLSL_1xx,
209
"#ifdef GL_ES\n"
210
"precision lowp float;\n"
211
"#endif\n"
212
"#if __VERSION__ >= 130\n"
213
"#define varying in\n"
214
"#define texture2D texture\n"
215
"#define gl_FragColor fragColor0\n"
216
"out vec4 fragColor0;\n"
217
"#endif\n"
218
"varying vec4 oColor0;\n"
219
"varying vec2 oTexCoord0;\n"
220
"uniform sampler2D Sampler0;\n"
221
"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0).zyxw * oColor0; }\n"
222
},
223
{ShaderLanguage::HLSL_D3D11,
224
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
225
"SamplerState samp : register(s0);\n"
226
"Texture2D<float4> tex : register(t0);\n"
227
"float4 main(PS_INPUT input) : SV_Target {\n"
228
" float4 col = input.color * tex.Sample(samp, input.uv).bgra;\n"
229
" return col;\n"
230
"}\n"
231
},
232
{ShaderLanguage::GLSL_VULKAN,
233
"#version 140\n"
234
"#extension GL_ARB_separate_shader_objects : enable\n"
235
"#extension GL_ARB_shading_language_420pack : enable\n"
236
"layout(location = 0) in vec4 oColor0;\n"
237
"layout(location = 1) in vec2 oTexCoord0;\n"
238
"layout(location = 0) out vec4 fragColor0\n;"
239
"layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n"
240
"void main() { fragColor0 = texture(Sampler0, oTexCoord0).bgra * oColor0; }\n"
241
}
242
};
243
244
static const std::vector<ShaderSource> fsCol = {
245
{ GLSL_1xx,
246
"#ifdef GL_ES\n"
247
"precision lowp float;\n"
248
"#endif\n"
249
"#if __VERSION__ >= 130\n"
250
"#define varying in\n"
251
"#define gl_FragColor fragColor0\n"
252
"out vec4 fragColor0;\n"
253
"#endif\n"
254
"varying vec4 oColor0;\n"
255
"void main() { gl_FragColor = oColor0; }\n"
256
},
257
{ ShaderLanguage::HLSL_D3D11,
258
"struct PS_INPUT { float4 color : COLOR0; };\n"
259
"float4 main(PS_INPUT input) : SV_Target {\n"
260
" return input.color;\n"
261
"}\n"
262
},
263
{ ShaderLanguage::GLSL_VULKAN,
264
"#version 140\n"
265
"#extension GL_ARB_separate_shader_objects : enable\n"
266
"#extension GL_ARB_shading_language_420pack : enable\n"
267
"layout(location = 0) in vec4 oColor0;\n"
268
"layout(location = 0) out vec4 fragColor0;\n"
269
"void main() { fragColor0 = oColor0; }\n"
270
}
271
};
272
273
// ================================== VERTEX SHADERS
274
275
static const std::vector<ShaderSource> vsCol = {
276
{ GLSL_1xx,
277
"#if __VERSION__ >= 130\n"
278
"#define attribute in\n"
279
"#define varying out\n"
280
"#endif\n"
281
"attribute vec3 Position;\n"
282
"attribute vec4 Color0;\n"
283
"varying vec4 oColor0;\n"
284
285
"uniform mat4 WorldViewProj;\n"
286
"uniform vec2 TintSaturation;\n"
287
"void main() {\n"
288
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
289
" oColor0 = Color0;\n"
290
"}"
291
},
292
{ ShaderLanguage::HLSL_D3D11,
293
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
294
"struct VS_OUTPUT { float4 Color0 : COLOR0; float4 Position : SV_Position; };\n"
295
"cbuffer ConstantBuffer : register(b0) {\n"
296
" matrix WorldViewProj;\n"
297
" float2 TintSaturation;\n"
298
"};\n"
299
"VS_OUTPUT main(VS_INPUT input) {\n"
300
" VS_OUTPUT output;\n"
301
" output.Position = mul(WorldViewProj, float4(input.Position, 1.0));\n"
302
" output.Color0 = input.Color0;\n"
303
" return output;\n"
304
"}\n"
305
},
306
{ ShaderLanguage::GLSL_VULKAN,
307
R"(#version 450
308
#extension GL_ARB_separate_shader_objects : enable
309
#extension GL_ARB_shading_language_420pack : enable
310
layout (std140, set = 0, binding = 0) uniform bufferVals {
311
mat4 WorldViewProj;
312
vec2 TintSaturation;
313
} myBufferVals;
314
layout (location = 0) in vec4 pos;
315
layout (location = 1) in vec4 inColor;
316
layout (location = 0) out vec4 outColor;
317
out gl_PerVertex { vec4 gl_Position; };
318
void main() {
319
outColor = inColor;
320
gl_Position = myBufferVals.WorldViewProj * pos;
321
}
322
)"
323
}
324
};
325
326
const UniformBufferDesc vsColBufDesc { sizeof(VsColUB), {
327
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 },
328
{ "TintSaturation", 4, -1, UniformType::FLOAT2, 64 },
329
} };
330
331
static const std::vector<ShaderSource> vsTexColNoTint = { {
332
GLSL_1xx,
333
R"(
334
#if __VERSION__ >= 130
335
#define attribute in
336
#define varying out
337
#endif
338
attribute vec3 Position;
339
attribute vec4 Color0;
340
attribute vec2 TexCoord0;
341
varying vec4 oColor0;
342
varying vec2 oTexCoord0;
343
uniform mat4 WorldViewProj;
344
uniform vec2 TintSaturation;
345
void main() {
346
gl_Position = WorldViewProj * vec4(Position, 1.0);
347
oColor0 = Color0;
348
oTexCoord0 = TexCoord0;
349
})"
350
} };
351
352
static const std::vector<ShaderSource> vsTexCol = {
353
{ GLSL_1xx,
354
R"(
355
#if __VERSION__ >= 130
356
#define attribute in
357
#define varying out
358
#endif
359
attribute vec3 Position;
360
attribute vec4 Color0;
361
attribute vec2 TexCoord0;
362
varying vec4 oColor0;
363
varying vec2 oTexCoord0;
364
uniform mat4 WorldViewProj;
365
uniform vec2 TintSaturation;
366
vec3 rgb2hsv(vec3 c) {
367
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
368
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
369
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
370
float d = q.x - min(q.w, q.y);
371
float e = 1.0e-10;
372
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
373
}
374
vec3 hsv2rgb(vec3 c) {
375
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
376
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
377
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
378
}
379
void main() {
380
gl_Position = WorldViewProj * vec4(Position, 1.0);
381
vec3 hsv = rgb2hsv(Color0.xyz);
382
hsv.x += TintSaturation.x;
383
hsv.y *= TintSaturation.y;
384
oColor0 = vec4(hsv2rgb(hsv), Color0.w);
385
oTexCoord0 = TexCoord0;
386
})",
387
},
388
{ ShaderLanguage::HLSL_D3D11,
389
R"(
390
struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
391
struct VS_OUTPUT { float4 Color0 : COLOR0; float2 Texcoord0 : TEXCOORD0; float4 Position : SV_Position; };
392
cbuffer ConstantBuffer : register(b0) {
393
matrix WorldViewProj;
394
float2 TintSaturation;
395
};
396
float3 rgb2hsv(float3 c) {
397
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
398
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
399
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
400
float d = q.x - min(q.w, q.y);
401
float e = 1.0e-10;
402
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
403
}
404
float3 hsv2rgb(float3 c) {
405
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
406
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
407
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
408
}
409
VS_OUTPUT main(VS_INPUT input) {
410
VS_OUTPUT output;
411
float3 hsv = rgb2hsv(input.Color0.xyz);
412
hsv.x += TintSaturation.x;
413
hsv.y *= TintSaturation.y;
414
output.Color0 = float4(hsv2rgb(hsv), input.Color0.w);
415
output.Position = mul(WorldViewProj, float4(input.Position, 1.0));
416
output.Texcoord0 = input.Texcoord0;
417
return output;
418
}
419
)"
420
},
421
{ ShaderLanguage::GLSL_VULKAN,
422
R"(#version 450
423
#extension GL_ARB_separate_shader_objects : enable
424
#extension GL_ARB_shading_language_420pack : enable
425
layout (std140, set = 0, binding = 0) uniform bufferVals {
426
mat4 WorldViewProj;
427
vec2 TintSaturation;
428
} myBufferVals;
429
vec3 rgb2hsv(vec3 c) {
430
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
431
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
432
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
433
float d = q.x - min(q.w, q.y);
434
float e = 1.0e-10;
435
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
436
}
437
vec3 hsv2rgb(vec3 c) {
438
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
439
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
440
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
441
}
442
layout (location = 0) in vec4 pos;
443
layout (location = 1) in vec4 inColor;
444
layout (location = 3) in vec2 inTexCoord;
445
layout (location = 0) out vec4 outColor;
446
layout (location = 1) out vec2 outTexCoord;
447
out gl_PerVertex { vec4 gl_Position; };
448
void main() {
449
vec3 hsv = rgb2hsv(inColor.xyz);
450
hsv.x += myBufferVals.TintSaturation.x;
451
hsv.y *= myBufferVals.TintSaturation.y;
452
outColor = vec4(hsv2rgb(hsv), inColor.w);
453
outTexCoord = inTexCoord;
454
gl_Position = myBufferVals.WorldViewProj * pos;
455
}
456
)"
457
} };
458
459
static_assert(SEM_TEXCOORD0 == 3, "Semantic shader hardcoded in glsl above.");
460
461
const UniformBufferDesc vsTexColBufDesc{ sizeof(VsTexColUB),{
462
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 },
463
{ "TintSaturation", 4, -1, UniformType::FLOAT2, 64 },
464
} };
465
466
ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources) {
467
uint32_t supported = draw->GetSupportedShaderLanguages();
468
for (const auto &iter : sources) {
469
if ((uint32_t)iter.lang & supported) {
470
return draw->CreateShaderModule(stage, iter.lang, (const uint8_t *)iter.src, strlen(iter.src));
471
}
472
}
473
return nullptr;
474
}
475
476
bool DrawContext::CreatePresets() {
477
if (bugs_.Has(Bugs::RASPBERRY_SHADER_COMP_HANG)) {
478
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::Vertex, vsTexColNoTint);
479
} else {
480
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::Vertex, vsTexCol);
481
}
482
483
vsPresets_[VS_COLOR_2D] = CreateShader(this, ShaderStage::Vertex, vsCol);
484
485
fsPresets_[FS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::Fragment, fsTexCol);
486
fsPresets_[FS_COLOR_2D] = CreateShader(this, ShaderStage::Fragment, fsCol);
487
fsPresets_[FS_TEXTURE_COLOR_2D_RB_SWIZZLE] = CreateShader(this, ShaderStage::Fragment, fsTexColRBSwizzle);
488
489
return vsPresets_[VS_TEXTURE_COLOR_2D] && vsPresets_[VS_COLOR_2D] && fsPresets_[FS_TEXTURE_COLOR_2D] && fsPresets_[FS_COLOR_2D] && fsPresets_[FS_TEXTURE_COLOR_2D_RB_SWIZZLE];
490
}
491
492
void DrawContext::DestroyPresets() {
493
for (int i = 0; i < VS_MAX_PRESET; i++) {
494
if (vsPresets_[i]) {
495
vsPresets_[i]->Release();
496
vsPresets_[i] = nullptr;
497
}
498
}
499
for (int i = 0; i < FS_MAX_PRESET; i++) {
500
if (fsPresets_[i]) {
501
fsPresets_[i]->Release();
502
fsPresets_[i] = nullptr;
503
}
504
}
505
}
506
507
void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
508
// Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP.
509
const uint32_t *src32 = (const uint32_t *)src;
510
511
if (format == Draw::DataFormat::R8G8B8A8_UNORM) {
512
uint32_t *dst32 = (uint32_t *)dst;
513
if (src == dst) {
514
return;
515
} else {
516
for (uint32_t y = 0; y < height; ++y) {
517
memcpy(dst32, src32, width * 4);
518
src32 += srcStride;
519
dst32 += dstStride;
520
}
521
}
522
} else if (format == Draw::DataFormat::R8G8B8_UNORM) {
523
for (uint32_t y = 0; y < height; ++y) {
524
ConvertRGBA8888ToRGB888(dst, src32, width);
525
src32 += srcStride;
526
dst += dstStride * 3;
527
}
528
} else {
529
// But here it shouldn't matter if they do intersect
530
uint16_t *dst16 = (uint16_t *)dst;
531
switch (format) {
532
case Draw::DataFormat::R5G6B5_UNORM_PACK16: // BGR 565
533
for (uint32_t y = 0; y < height; ++y) {
534
ConvertRGBA8888ToRGB565(dst16, src32, width);
535
src32 += srcStride;
536
dst16 += dstStride;
537
}
538
break;
539
case Draw::DataFormat::A1R5G5B5_UNORM_PACK16: // ABGR 1555
540
for (uint32_t y = 0; y < height; ++y) {
541
ConvertRGBA8888ToRGBA5551(dst16, src32, width);
542
src32 += srcStride;
543
dst16 += dstStride;
544
}
545
break;
546
case Draw::DataFormat::A4R4G4B4_UNORM_PACK16: // ABGR 4444
547
for (uint32_t y = 0; y < height; ++y) {
548
ConvertRGBA8888ToRGBA4444(dst16, src32, width);
549
src32 += srcStride;
550
dst16 += dstStride;
551
}
552
break;
553
case Draw::DataFormat::R8G8B8A8_UNORM:
554
case Draw::DataFormat::UNDEFINED:
555
default:
556
WARN_LOG(Log::G3D, "Unable to convert from format: %d", (int)format);
557
break;
558
}
559
}
560
}
561
562
void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
563
// Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP.
564
const uint32_t *src32 = (const uint32_t *)src;
565
566
if (format == Draw::DataFormat::B8G8R8A8_UNORM) {
567
uint32_t *dst32 = (uint32_t *)dst;
568
if (src == dst) {
569
return;
570
} else {
571
for (uint32_t y = 0; y < height; ++y) {
572
memcpy(dst32, src32, width * 4);
573
src32 += srcStride;
574
dst32 += dstStride;
575
}
576
}
577
} else if (format == Draw::DataFormat::R8G8B8A8_UNORM) {
578
uint32_t *dst32 = (uint32_t *)dst;
579
for (uint32_t y = 0; y < height; ++y) {
580
ConvertBGRA8888ToRGBA8888(dst32, src32, width);
581
src32 += srcStride;
582
dst32 += dstStride;
583
}
584
} else if (format == Draw::DataFormat::R8G8B8_UNORM) {
585
for (uint32_t y = 0; y < height; ++y) {
586
ConvertBGRA8888ToRGB888(dst, src32, width);
587
src32 += srcStride;
588
dst += dstStride * 3;
589
}
590
} else {
591
// But here it shouldn't matter if they do intersect
592
uint16_t *dst16 = (uint16_t *)dst;
593
switch (format) {
594
case Draw::DataFormat::R5G6B5_UNORM_PACK16: // BGR 565
595
for (uint32_t y = 0; y < height; ++y) {
596
ConvertBGRA8888ToRGB565(dst16, src32, width);
597
src32 += srcStride;
598
dst16 += dstStride;
599
}
600
break;
601
case Draw::DataFormat::A1R5G5B5_UNORM_PACK16: // ABGR 1555
602
for (uint32_t y = 0; y < height; ++y) {
603
ConvertBGRA8888ToRGBA5551(dst16, src32, width);
604
src32 += srcStride;
605
dst16 += dstStride;
606
}
607
break;
608
case Draw::DataFormat::A4R4G4B4_UNORM_PACK16: // ABGR 4444
609
for (uint32_t y = 0; y < height; ++y) {
610
ConvertBGRA8888ToRGBA4444(dst16, src32, width);
611
src32 += srcStride;
612
dst16 += dstStride;
613
}
614
break;
615
case Draw::DataFormat::R8G8B8A8_UNORM:
616
case Draw::DataFormat::UNDEFINED:
617
default:
618
WARN_LOG(Log::G3D, "Unable to convert from format to BGRA: %d", (int)format);
619
break;
620
}
621
}
622
}
623
624
void ConvertToD32F(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
625
if (format == Draw::DataFormat::D32F) {
626
const float *src32 = (const float *)src;
627
float *dst32 = (float *)dst;
628
if (src == dst) {
629
return;
630
} else {
631
for (uint32_t y = 0; y < height; ++y) {
632
memcpy(dst32, src32, width * 4);
633
src32 += srcStride;
634
dst32 += dstStride;
635
}
636
}
637
} else if (format == Draw::DataFormat::D16) {
638
const uint16_t *src16 = (const uint16_t *)src;
639
float *dst32 = (float *)dst;
640
for (uint32_t y = 0; y < height; ++y) {
641
for (uint32_t x = 0; x < width; ++x) {
642
dst32[x] = (float)(int)src16[x] / 65535.0f;
643
}
644
src16 += srcStride;
645
dst32 += dstStride;
646
}
647
} else if (format == Draw::DataFormat::D24_S8) {
648
const uint32_t *src32 = (const uint32_t *)src;
649
float *dst32 = (float *)dst;
650
for (uint32_t y = 0; y < height; ++y) {
651
for (uint32_t x = 0; x < width; ++x) {
652
dst32[x] = (src32[x] & 0x00FFFFFF) / 16777215.0f;
653
}
654
src32 += srcStride;
655
dst32 += dstStride;
656
}
657
} else {
658
assert(false);
659
}
660
}
661
662
// TODO: This is missing the conversion to the quarter-range we use if depth clamp is not available.
663
// That conversion doesn't necessarily belong here in thin3d, though.
664
void ConvertToD16(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
665
if (format == Draw::DataFormat::D32F) {
666
const float *src32 = (const float *)src;
667
uint16_t *dst16 = (uint16_t *)dst;
668
if (src == dst) {
669
return;
670
} else {
671
for (uint32_t y = 0; y < height; ++y) {
672
for (uint32_t x = 0; x < width; ++x) {
673
dst16[x] = (uint16_t)(src32[x] * 65535.0f);
674
}
675
src32 += srcStride;
676
dst16 += dstStride;
677
}
678
}
679
} else if (format == Draw::DataFormat::D16) {
680
_assert_(src != dst);
681
const uint16_t *src16 = (const uint16_t *)src;
682
uint16_t *dst16 = (uint16_t *)dst;
683
for (uint32_t y = 0; y < height; ++y) {
684
memcpy(dst16, src16, width * 2);
685
src16 += srcStride;
686
dst16 += dstStride;
687
}
688
} else if (format == Draw::DataFormat::D24_S8) {
689
_assert_(src != dst);
690
const uint32_t *src32 = (const uint32_t *)src;
691
uint16_t *dst16 = (uint16_t *)dst;
692
for (uint32_t y = 0; y < height; ++y) {
693
for (uint32_t x = 0; x < width; ++x) {
694
dst16[x] = (src32[x] & 0x00FFFFFF) >> 8;
695
}
696
src32 += srcStride;
697
dst16 += dstStride;
698
}
699
} else {
700
assert(false);
701
}
702
}
703
704
const char *Bugs::GetBugName(uint32_t bug) {
705
switch (bug) {
706
case NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI: return "NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI";
707
case NO_DEPTH_CANNOT_DISCARD_STENCIL_ADRENO: return "NO_DEPTH_CANNOT_DISCARD_STENCIL_ADRENO";
708
case DUAL_SOURCE_BLENDING_BROKEN: return "DUAL_SOURCE_BLENDING_BROKEN";
709
case ANY_MAP_BUFFER_RANGE_SLOW: return "ANY_MAP_BUFFER_RANGE_SLOW";
710
case PVR_GENMIPMAP_HEIGHT_GREATER: return "PVR_GENMIPMAP_HEIGHT_GREATER";
711
case BROKEN_NAN_IN_CONDITIONAL: return "BROKEN_NAN_IN_CONDITIONAL";
712
case COLORWRITEMASK_BROKEN_WITH_DEPTHTEST: return "COLORWRITEMASK_BROKEN_WITH_DEPTHTEST";
713
case BROKEN_FLAT_IN_SHADER: return "BROKEN_FLAT_IN_SHADER";
714
case EQUAL_WZ_CORRUPTS_DEPTH: return "EQUAL_WZ_CORRUPTS_DEPTH";
715
case RASPBERRY_SHADER_COMP_HANG: return "RASPBERRY_SHADER_COMP_HANG";
716
case MALI_CONSTANT_LOAD_BUG: return "MALI_CONSTANT_LOAD_BUG";
717
case SUBPASS_FEEDBACK_BROKEN: return "SUBPASS_FEEDBACK_BROKEN";
718
case GEOMETRY_SHADERS_SLOW_OR_BROKEN: return "GEOMETRY_SHADERS_SLOW_OR_BROKEN";
719
case ADRENO_RESOURCE_DEADLOCK: return "ADRENO_RESOURCE_DEADLOCK";
720
case PVR_BAD_16BIT_TEXFORMATS: return "PVR_BAD_16BIT_TEXFORMATS";
721
default: return "(N/A)";
722
}
723
}
724
725
const char *PresentModeToString(PresentMode presentMode) {
726
// All 8 possible cases, with three flags, for simplicity.
727
switch ((int)presentMode) {
728
case 0: return "NONE";
729
case (int)PresentMode::FIFO: return "FIFO";
730
case (int)PresentMode::IMMEDIATE: return "IMMEDIATE";
731
case (int)PresentMode::MAILBOX: return "MAILBOX";
732
case ((int)PresentMode::FIFO | (int)PresentMode::MAILBOX) : return "FIFO|MAILBOX";
733
case ((int)PresentMode::FIFO | (int)PresentMode::IMMEDIATE) : return "FIFO|IMMEDIATE";
734
case ((int)PresentMode::MAILBOX | (int)PresentMode::IMMEDIATE) : return "MAILBOX|IMMEDIATE"; // Not gonna happen
735
case ((int)PresentMode::FIFO | (int)PresentMode::MAILBOX | (int)PresentMode::IMMEDIATE) : return "FIFO|MAILBOX|IMMEDIATE";
736
default:
737
return "INVALID";
738
}
739
}
740
741
} // namespace Draw
742
743