CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/thin3d.cpp
Views: 1401
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
RefCountedObject::~RefCountedObject() {
122
const int rc = refcount_.load();
123
_dbg_assert_msg_(rc == 0xDEDEDE, "Unexpected refcount %d in object of type '%s'", rc, name_);
124
}
125
126
bool RefCountedObject::Release() {
127
if (refcount_ > 0 && refcount_ < 10000) {
128
if (--refcount_ == 0) {
129
// Make it very obvious if we try to free this again.
130
refcount_ = 0xDEDEDE;
131
delete this;
132
return true;
133
}
134
} else {
135
// No point in printing the name here if the object has already been free-d, it'll be corrupt and dangerous to print.
136
_dbg_assert_msg_(false, "Refcount (%d) invalid for object %p - corrupt?", refcount_.load(), this);
137
}
138
return false;
139
}
140
141
bool RefCountedObject::ReleaseAssertLast() {
142
bool released = Release();
143
_dbg_assert_msg_(released, "RefCountedObject: Expected to be the last reference, but isn't! (%s)", name_);
144
return released;
145
}
146
147
// ================================== PIXEL/FRAGMENT SHADERS
148
149
// The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL.
150
151
static const std::vector<ShaderSource> fsTexCol = {
152
{ShaderLanguage::GLSL_1xx,
153
"#ifdef GL_ES\n"
154
"precision lowp float;\n"
155
"#endif\n"
156
"#if __VERSION__ >= 130\n"
157
"#define varying in\n"
158
"#define texture2D texture\n"
159
"#define gl_FragColor fragColor0\n"
160
"out vec4 fragColor0;\n"
161
"#endif\n"
162
"varying vec4 oColor0;\n"
163
"varying vec2 oTexCoord0;\n"
164
"uniform sampler2D Sampler0;\n"
165
"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0) * oColor0; }\n"
166
},
167
{ShaderLanguage::HLSL_D3D9,
168
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
169
"sampler2D Sampler0 : register(s0);\n"
170
"float4 main(PS_INPUT input) : COLOR0 {\n"
171
" return input.color * tex2D(Sampler0, input.uv);\n"
172
"}\n"
173
},
174
{ShaderLanguage::HLSL_D3D11,
175
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
176
"SamplerState samp : register(s0);\n"
177
"Texture2D<float4> tex : register(t0);\n"
178
"float4 main(PS_INPUT input) : SV_Target {\n"
179
" float4 col = input.color * tex.Sample(samp, input.uv);\n"
180
" return col;\n"
181
"}\n"
182
},
183
{ShaderLanguage::GLSL_VULKAN,
184
"#version 140\n"
185
"#extension GL_ARB_separate_shader_objects : enable\n"
186
"#extension GL_ARB_shading_language_420pack : enable\n"
187
"layout(location = 0) in vec4 oColor0;\n"
188
"layout(location = 1) in vec2 oTexCoord0;\n"
189
"layout(location = 0) out vec4 fragColor0;\n"
190
"layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n"
191
"void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n"
192
}
193
};
194
195
static const std::vector<ShaderSource> fsTexColRBSwizzle = {
196
{GLSL_1xx,
197
"#ifdef GL_ES\n"
198
"precision lowp float;\n"
199
"#endif\n"
200
"#if __VERSION__ >= 130\n"
201
"#define varying in\n"
202
"#define texture2D texture\n"
203
"#define gl_FragColor fragColor0\n"
204
"out vec4 fragColor0;\n"
205
"#endif\n"
206
"varying vec4 oColor0;\n"
207
"varying vec2 oTexCoord0;\n"
208
"uniform sampler2D Sampler0;\n"
209
"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0).zyxw * oColor0; }\n"
210
},
211
{ShaderLanguage::HLSL_D3D9,
212
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
213
"sampler2D Sampler0 : register(s0);\n"
214
"float4 main(PS_INPUT input) : COLOR0 {\n"
215
" return input.color * tex2D(Sampler0, input.uv).zyxw;\n"
216
"}\n"
217
},
218
{ShaderLanguage::HLSL_D3D11,
219
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
220
"SamplerState samp : register(s0);\n"
221
"Texture2D<float4> tex : register(t0);\n"
222
"float4 main(PS_INPUT input) : SV_Target {\n"
223
" float4 col = input.color * tex.Sample(samp, input.uv).bgra;\n"
224
" return col;\n"
225
"}\n"
226
},
227
{ShaderLanguage::GLSL_VULKAN,
228
"#version 140\n"
229
"#extension GL_ARB_separate_shader_objects : enable\n"
230
"#extension GL_ARB_shading_language_420pack : enable\n"
231
"layout(location = 0) in vec4 oColor0;\n"
232
"layout(location = 1) in vec2 oTexCoord0;\n"
233
"layout(location = 0) out vec4 fragColor0\n;"
234
"layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n"
235
"void main() { fragColor0 = texture(Sampler0, oTexCoord0).bgra * oColor0; }\n"
236
}
237
};
238
239
static const std::vector<ShaderSource> fsCol = {
240
{ GLSL_1xx,
241
"#ifdef GL_ES\n"
242
"precision lowp float;\n"
243
"#endif\n"
244
"#if __VERSION__ >= 130\n"
245
"#define varying in\n"
246
"#define gl_FragColor fragColor0\n"
247
"out vec4 fragColor0;\n"
248
"#endif\n"
249
"varying vec4 oColor0;\n"
250
"void main() { gl_FragColor = oColor0; }\n"
251
},
252
{ ShaderLanguage::HLSL_D3D9,
253
"struct PS_INPUT { float4 color : COLOR0; };\n"
254
"float4 main(PS_INPUT input) : COLOR0 {\n"
255
" return input.color;\n"
256
"}\n"
257
},
258
{ ShaderLanguage::HLSL_D3D11,
259
"struct PS_INPUT { float4 color : COLOR0; };\n"
260
"float4 main(PS_INPUT input) : SV_Target {\n"
261
" return input.color;\n"
262
"}\n"
263
},
264
{ ShaderLanguage::GLSL_VULKAN,
265
"#version 140\n"
266
"#extension GL_ARB_separate_shader_objects : enable\n"
267
"#extension GL_ARB_shading_language_420pack : enable\n"
268
"layout(location = 0) in vec4 oColor0;\n"
269
"layout(location = 0) out vec4 fragColor0;\n"
270
"void main() { fragColor0 = oColor0; }\n"
271
}
272
};
273
274
// ================================== VERTEX SHADERS
275
276
static const std::vector<ShaderSource> vsCol = {
277
{ GLSL_1xx,
278
"#if __VERSION__ >= 130\n"
279
"#define attribute in\n"
280
"#define varying out\n"
281
"#endif\n"
282
"attribute vec3 Position;\n"
283
"attribute vec4 Color0;\n"
284
"varying vec4 oColor0;\n"
285
286
"uniform mat4 WorldViewProj;\n"
287
"uniform vec2 TintSaturation;\n"
288
"void main() {\n"
289
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
290
" oColor0 = Color0;\n"
291
"}"
292
},
293
{ ShaderLanguage::HLSL_D3D9,
294
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
295
"struct VS_OUTPUT { float4 Position : POSITION; float4 Color0 : COLOR0; };\n"
296
"float4x4 WorldViewProj : register(c0);\n"
297
"float2 TintSaturation : register(c4);\n"
298
"VS_OUTPUT main(VS_INPUT input) {\n"
299
" VS_OUTPUT output;\n"
300
" output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
301
" output.Color0 = input.Color0;\n"
302
" return output;\n"
303
"}\n"
304
},
305
{ ShaderLanguage::HLSL_D3D11,
306
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
307
"struct VS_OUTPUT { float4 Color0 : COLOR0; float4 Position : SV_Position; };\n"
308
"cbuffer ConstantBuffer : register(b0) {\n"
309
" matrix WorldViewProj;\n"
310
" float2 TintSaturation;\n"
311
"};\n"
312
"VS_OUTPUT main(VS_INPUT input) {\n"
313
" VS_OUTPUT output;\n"
314
" output.Position = mul(WorldViewProj, float4(input.Position, 1.0));\n"
315
" output.Color0 = input.Color0;\n"
316
" return output;\n"
317
"}\n"
318
},
319
{ ShaderLanguage::GLSL_VULKAN,
320
R"(#version 450
321
#extension GL_ARB_separate_shader_objects : enable
322
#extension GL_ARB_shading_language_420pack : enable
323
layout (std140, set = 0, binding = 0) uniform bufferVals {
324
mat4 WorldViewProj;
325
vec2 TintSaturation;
326
} myBufferVals;
327
layout (location = 0) in vec4 pos;
328
layout (location = 1) in vec4 inColor;
329
layout (location = 0) out vec4 outColor;
330
out gl_PerVertex { vec4 gl_Position; };
331
void main() {
332
outColor = inColor;
333
gl_Position = myBufferVals.WorldViewProj * pos;
334
}
335
)"
336
}
337
};
338
339
const UniformBufferDesc vsColBufDesc { sizeof(VsColUB), {
340
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 },
341
{ "TintSaturation", 4, -1, UniformType::FLOAT2, 64 },
342
} };
343
344
static const std::vector<ShaderSource> vsTexColNoTint = { {
345
GLSL_1xx,
346
R"(
347
#if __VERSION__ >= 130
348
#define attribute in
349
#define varying out
350
#endif
351
attribute vec3 Position;
352
attribute vec4 Color0;
353
attribute vec2 TexCoord0;
354
varying vec4 oColor0;
355
varying vec2 oTexCoord0;
356
uniform mat4 WorldViewProj;
357
uniform vec2 TintSaturation;
358
void main() {
359
gl_Position = WorldViewProj * vec4(Position, 1.0);
360
oColor0 = Color0;
361
oTexCoord0 = TexCoord0;
362
})"
363
} };
364
365
static const std::vector<ShaderSource> vsTexCol = {
366
{ GLSL_1xx,
367
R"(
368
#if __VERSION__ >= 130
369
#define attribute in
370
#define varying out
371
#endif
372
attribute vec3 Position;
373
attribute vec4 Color0;
374
attribute vec2 TexCoord0;
375
varying vec4 oColor0;
376
varying vec2 oTexCoord0;
377
uniform mat4 WorldViewProj;
378
uniform vec2 TintSaturation;
379
vec3 rgb2hsv(vec3 c) {
380
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
381
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
382
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
383
float d = q.x - min(q.w, q.y);
384
float e = 1.0e-10;
385
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
386
}
387
vec3 hsv2rgb(vec3 c) {
388
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
389
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
390
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
391
}
392
void main() {
393
gl_Position = WorldViewProj * vec4(Position, 1.0);
394
vec3 hsv = rgb2hsv(Color0.xyz);
395
hsv.x += TintSaturation.x;
396
hsv.y *= TintSaturation.y;
397
oColor0 = vec4(hsv2rgb(hsv), Color0.w);
398
oTexCoord0 = TexCoord0;
399
})",
400
},
401
{ ShaderLanguage::HLSL_D3D9,
402
R"(
403
struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
404
struct VS_OUTPUT { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
405
float4x4 WorldViewProj : register(c0);
406
float2 TintSaturation : register(c4);
407
float3 rgb2hsv(float3 c) {
408
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
409
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
410
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
411
float d = q.x - min(q.w, q.y);
412
float e = 1.0e-10;
413
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
414
}
415
float3 hsv2rgb(float3 c) {
416
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
417
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
418
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
419
}
420
VS_OUTPUT main(VS_INPUT input) {
421
VS_OUTPUT output;
422
float3 hsv = rgb2hsv(input.Color0.xyz);
423
hsv.x += TintSaturation.x;
424
hsv.y *= TintSaturation.y;
425
output.Color0 = float4(hsv2rgb(hsv), input.Color0.w);
426
output.Position = mul(float4(input.Position, 1.0), WorldViewProj);
427
output.Texcoord0 = input.Texcoord0;
428
return output;
429
}
430
)"
431
},
432
{ ShaderLanguage::HLSL_D3D11,
433
R"(
434
struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
435
struct VS_OUTPUT { float4 Color0 : COLOR0; float2 Texcoord0 : TEXCOORD0; float4 Position : SV_Position; };
436
cbuffer ConstantBuffer : register(b0) {
437
matrix WorldViewProj;
438
float2 TintSaturation;
439
};
440
float3 rgb2hsv(float3 c) {
441
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
442
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
443
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
444
float d = q.x - min(q.w, q.y);
445
float e = 1.0e-10;
446
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
447
}
448
float3 hsv2rgb(float3 c) {
449
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
450
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
451
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
452
}
453
VS_OUTPUT main(VS_INPUT input) {
454
VS_OUTPUT output;
455
float3 hsv = rgb2hsv(input.Color0.xyz);
456
hsv.x += TintSaturation.x;
457
hsv.y *= TintSaturation.y;
458
output.Color0 = float4(hsv2rgb(hsv), input.Color0.w);
459
output.Position = mul(WorldViewProj, float4(input.Position, 1.0));
460
output.Texcoord0 = input.Texcoord0;
461
return output;
462
}
463
)"
464
},
465
{ ShaderLanguage::GLSL_VULKAN,
466
R"(#version 450
467
#extension GL_ARB_separate_shader_objects : enable
468
#extension GL_ARB_shading_language_420pack : enable
469
layout (std140, set = 0, binding = 0) uniform bufferVals {
470
mat4 WorldViewProj;
471
vec2 TintSaturation;
472
} myBufferVals;
473
vec3 rgb2hsv(vec3 c) {
474
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
475
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
476
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
477
float d = q.x - min(q.w, q.y);
478
float e = 1.0e-10;
479
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
480
}
481
vec3 hsv2rgb(vec3 c) {
482
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
483
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
484
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
485
}
486
layout (location = 0) in vec4 pos;
487
layout (location = 1) in vec4 inColor;
488
layout (location = 3) in vec2 inTexCoord;
489
layout (location = 0) out vec4 outColor;
490
layout (location = 1) out vec2 outTexCoord;
491
out gl_PerVertex { vec4 gl_Position; };
492
void main() {
493
vec3 hsv = rgb2hsv(inColor.xyz);
494
hsv.x += myBufferVals.TintSaturation.x;
495
hsv.y *= myBufferVals.TintSaturation.y;
496
outColor = vec4(hsv2rgb(hsv), inColor.w);
497
outTexCoord = inTexCoord;
498
gl_Position = myBufferVals.WorldViewProj * pos;
499
}
500
)"
501
} };
502
503
static_assert(SEM_TEXCOORD0 == 3, "Semantic shader hardcoded in glsl above.");
504
505
const UniformBufferDesc vsTexColBufDesc{ sizeof(VsTexColUB),{
506
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 },
507
{ "TintSaturation", 4, -1, UniformType::FLOAT2, 64 },
508
} };
509
510
ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources) {
511
uint32_t supported = draw->GetSupportedShaderLanguages();
512
for (auto iter : sources) {
513
if ((uint32_t)iter.lang & supported) {
514
return draw->CreateShaderModule(stage, iter.lang, (const uint8_t *)iter.src, strlen(iter.src));
515
}
516
}
517
return nullptr;
518
}
519
520
bool DrawContext::CreatePresets() {
521
if (bugs_.Has(Bugs::RASPBERRY_SHADER_COMP_HANG)) {
522
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::Vertex, vsTexColNoTint);
523
} else {
524
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::Vertex, vsTexCol);
525
}
526
527
vsPresets_[VS_COLOR_2D] = CreateShader(this, ShaderStage::Vertex, vsCol);
528
529
fsPresets_[FS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::Fragment, fsTexCol);
530
fsPresets_[FS_COLOR_2D] = CreateShader(this, ShaderStage::Fragment, fsCol);
531
fsPresets_[FS_TEXTURE_COLOR_2D_RB_SWIZZLE] = CreateShader(this, ShaderStage::Fragment, fsTexColRBSwizzle);
532
533
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];
534
}
535
536
void DrawContext::DestroyPresets() {
537
for (int i = 0; i < VS_MAX_PRESET; i++) {
538
if (vsPresets_[i]) {
539
vsPresets_[i]->Release();
540
vsPresets_[i] = nullptr;
541
}
542
}
543
for (int i = 0; i < FS_MAX_PRESET; i++) {
544
if (fsPresets_[i]) {
545
fsPresets_[i]->Release();
546
fsPresets_[i] = nullptr;
547
}
548
}
549
}
550
551
DrawContext::~DrawContext() {
552
// TODO: Can't call DestroyPresets here, too late.
553
}
554
555
void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
556
// Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP.
557
const uint32_t *src32 = (const uint32_t *)src;
558
559
if (format == Draw::DataFormat::R8G8B8A8_UNORM) {
560
uint32_t *dst32 = (uint32_t *)dst;
561
if (src == dst) {
562
return;
563
} else {
564
for (uint32_t y = 0; y < height; ++y) {
565
memcpy(dst32, src32, width * 4);
566
src32 += srcStride;
567
dst32 += dstStride;
568
}
569
}
570
} else if (format == Draw::DataFormat::R8G8B8_UNORM) {
571
for (uint32_t y = 0; y < height; ++y) {
572
ConvertRGBA8888ToRGB888(dst, src32, width);
573
src32 += srcStride;
574
dst += dstStride * 3;
575
}
576
} else {
577
// But here it shouldn't matter if they do intersect
578
uint16_t *dst16 = (uint16_t *)dst;
579
switch (format) {
580
case Draw::DataFormat::R5G6B5_UNORM_PACK16: // BGR 565
581
for (uint32_t y = 0; y < height; ++y) {
582
ConvertRGBA8888ToRGB565(dst16, src32, width);
583
src32 += srcStride;
584
dst16 += dstStride;
585
}
586
break;
587
case Draw::DataFormat::A1R5G5B5_UNORM_PACK16: // ABGR 1555
588
for (uint32_t y = 0; y < height; ++y) {
589
ConvertRGBA8888ToRGBA5551(dst16, src32, width);
590
src32 += srcStride;
591
dst16 += dstStride;
592
}
593
break;
594
case Draw::DataFormat::A4R4G4B4_UNORM_PACK16: // ABGR 4444
595
for (uint32_t y = 0; y < height; ++y) {
596
ConvertRGBA8888ToRGBA4444(dst16, src32, width);
597
src32 += srcStride;
598
dst16 += dstStride;
599
}
600
break;
601
case Draw::DataFormat::R8G8B8A8_UNORM:
602
case Draw::DataFormat::UNDEFINED:
603
default:
604
WARN_LOG(Log::G3D, "Unable to convert from format: %d", (int)format);
605
break;
606
}
607
}
608
}
609
610
void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
611
// Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP.
612
const uint32_t *src32 = (const uint32_t *)src;
613
614
if (format == Draw::DataFormat::B8G8R8A8_UNORM) {
615
uint32_t *dst32 = (uint32_t *)dst;
616
if (src == dst) {
617
return;
618
} else {
619
for (uint32_t y = 0; y < height; ++y) {
620
memcpy(dst32, src32, width * 4);
621
src32 += srcStride;
622
dst32 += dstStride;
623
}
624
}
625
} else if (format == Draw::DataFormat::R8G8B8A8_UNORM) {
626
uint32_t *dst32 = (uint32_t *)dst;
627
for (uint32_t y = 0; y < height; ++y) {
628
ConvertBGRA8888ToRGBA8888(dst32, src32, width);
629
src32 += srcStride;
630
dst32 += dstStride;
631
}
632
} else if (format == Draw::DataFormat::R8G8B8_UNORM) {
633
for (uint32_t y = 0; y < height; ++y) {
634
ConvertBGRA8888ToRGB888(dst, src32, width);
635
src32 += srcStride;
636
dst += dstStride * 3;
637
}
638
} else {
639
// But here it shouldn't matter if they do intersect
640
uint16_t *dst16 = (uint16_t *)dst;
641
switch (format) {
642
case Draw::DataFormat::R5G6B5_UNORM_PACK16: // BGR 565
643
for (uint32_t y = 0; y < height; ++y) {
644
ConvertBGRA8888ToRGB565(dst16, src32, width);
645
src32 += srcStride;
646
dst16 += dstStride;
647
}
648
break;
649
case Draw::DataFormat::A1R5G5B5_UNORM_PACK16: // ABGR 1555
650
for (uint32_t y = 0; y < height; ++y) {
651
ConvertBGRA8888ToRGBA5551(dst16, src32, width);
652
src32 += srcStride;
653
dst16 += dstStride;
654
}
655
break;
656
case Draw::DataFormat::A4R4G4B4_UNORM_PACK16: // ABGR 4444
657
for (uint32_t y = 0; y < height; ++y) {
658
ConvertBGRA8888ToRGBA4444(dst16, src32, width);
659
src32 += srcStride;
660
dst16 += dstStride;
661
}
662
break;
663
case Draw::DataFormat::R8G8B8A8_UNORM:
664
case Draw::DataFormat::UNDEFINED:
665
default:
666
WARN_LOG(Log::G3D, "Unable to convert from format to BGRA: %d", (int)format);
667
break;
668
}
669
}
670
}
671
672
void ConvertToD32F(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
673
if (format == Draw::DataFormat::D32F) {
674
const float *src32 = (const float *)src;
675
float *dst32 = (float *)dst;
676
if (src == dst) {
677
return;
678
} else {
679
for (uint32_t y = 0; y < height; ++y) {
680
memcpy(dst32, src32, width * 4);
681
src32 += srcStride;
682
dst32 += dstStride;
683
}
684
}
685
} else if (format == Draw::DataFormat::D16) {
686
const uint16_t *src16 = (const uint16_t *)src;
687
float *dst32 = (float *)dst;
688
for (uint32_t y = 0; y < height; ++y) {
689
for (uint32_t x = 0; x < width; ++x) {
690
dst32[x] = (float)(int)src16[x] / 65535.0f;
691
}
692
src16 += srcStride;
693
dst32 += dstStride;
694
}
695
} else if (format == Draw::DataFormat::D24_S8) {
696
const uint32_t *src32 = (const uint32_t *)src;
697
float *dst32 = (float *)dst;
698
for (uint32_t y = 0; y < height; ++y) {
699
for (uint32_t x = 0; x < width; ++x) {
700
dst32[x] = (src32[x] & 0x00FFFFFF) / 16777215.0f;
701
}
702
src32 += srcStride;
703
dst32 += dstStride;
704
}
705
} else {
706
assert(false);
707
}
708
}
709
710
// TODO: This is missing the conversion to the quarter-range we use if depth clamp is not available.
711
// That conversion doesn't necessarily belong here in thin3d, though.
712
void ConvertToD16(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
713
if (format == Draw::DataFormat::D32F) {
714
const float *src32 = (const float *)src;
715
uint16_t *dst16 = (uint16_t *)dst;
716
if (src == dst) {
717
return;
718
} else {
719
for (uint32_t y = 0; y < height; ++y) {
720
for (uint32_t x = 0; x < width; ++x) {
721
dst16[x] = (uint16_t)(src32[x] * 65535.0f);
722
}
723
src32 += srcStride;
724
dst16 += dstStride;
725
}
726
}
727
} else if (format == Draw::DataFormat::D16) {
728
_assert_(src != dst);
729
const uint16_t *src16 = (const uint16_t *)src;
730
uint16_t *dst16 = (uint16_t *)dst;
731
for (uint32_t y = 0; y < height; ++y) {
732
memcpy(dst16, src16, width * 2);
733
src16 += srcStride;
734
dst16 += dstStride;
735
}
736
} else if (format == Draw::DataFormat::D24_S8) {
737
_assert_(src != dst);
738
const uint32_t *src32 = (const uint32_t *)src;
739
uint16_t *dst16 = (uint16_t *)dst;
740
for (uint32_t y = 0; y < height; ++y) {
741
for (uint32_t x = 0; x < width; ++x) {
742
dst16[x] = (src32[x] & 0x00FFFFFF) >> 8;
743
}
744
src32 += srcStride;
745
dst16 += dstStride;
746
}
747
} else {
748
assert(false);
749
}
750
}
751
752
const char *Bugs::GetBugName(uint32_t bug) {
753
switch (bug) {
754
case NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI: return "NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI";
755
case NO_DEPTH_CANNOT_DISCARD_STENCIL_ADRENO: return "NO_DEPTH_CANNOT_DISCARD_STENCIL_ADRENO";
756
case DUAL_SOURCE_BLENDING_BROKEN: return "DUAL_SOURCE_BLENDING_BROKEN";
757
case ANY_MAP_BUFFER_RANGE_SLOW: return "ANY_MAP_BUFFER_RANGE_SLOW";
758
case PVR_GENMIPMAP_HEIGHT_GREATER: return "PVR_GENMIPMAP_HEIGHT_GREATER";
759
case BROKEN_NAN_IN_CONDITIONAL: return "BROKEN_NAN_IN_CONDITIONAL";
760
case COLORWRITEMASK_BROKEN_WITH_DEPTHTEST: return "COLORWRITEMASK_BROKEN_WITH_DEPTHTEST";
761
case BROKEN_FLAT_IN_SHADER: return "BROKEN_FLAT_IN_SHADER";
762
case EQUAL_WZ_CORRUPTS_DEPTH: return "EQUAL_WZ_CORRUPTS_DEPTH";
763
case RASPBERRY_SHADER_COMP_HANG: return "RASPBERRY_SHADER_COMP_HANG";
764
case MALI_CONSTANT_LOAD_BUG: return "MALI_CONSTANT_LOAD_BUG";
765
case SUBPASS_FEEDBACK_BROKEN: return "SUBPASS_FEEDBACK_BROKEN";
766
case GEOMETRY_SHADERS_SLOW_OR_BROKEN: return "GEOMETRY_SHADERS_SLOW_OR_BROKEN";
767
case ADRENO_RESOURCE_DEADLOCK: return "ADRENO_RESOURCE_DEADLOCK";
768
case PVR_BAD_16BIT_TEXFORMATS: return "PVR_BAD_16BIT_TEXFORMATS";
769
default: return "(N/A)";
770
}
771
}
772
773
const char *PresentModeToString(PresentMode presentMode) {
774
// All 8 possible cases, with three flags, for simplicity.
775
switch ((int)presentMode) {
776
case 0: return "NONE";
777
case (int)PresentMode::FIFO: return "FIFO";
778
case (int)PresentMode::IMMEDIATE: return "IMMEDIATE";
779
case (int)PresentMode::MAILBOX: return "MAILBOX";
780
case ((int)PresentMode::FIFO | (int)PresentMode::MAILBOX) : return "FIFO|MAILBOX";
781
case ((int)PresentMode::FIFO | (int)PresentMode::IMMEDIATE) : return "FIFO|IMMEDIATE";
782
case ((int)PresentMode::MAILBOX | (int)PresentMode::IMMEDIATE) : return "MAILBOX|IMMEDIATE"; // Not gonna happen
783
case ((int)PresentMode::FIFO | (int)PresentMode::MAILBOX | (int)PresentMode::IMMEDIATE) : return "FIFO|MAILBOX|IMMEDIATE";
784
default:
785
return "INVALID";
786
}
787
}
788
789
} // namespace Draw
790
791