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/OpenGL/GLQueueRunner.cpp
Views: 1401
1
#include "ppsspp_config.h"
2
#include <algorithm>
3
4
#include "Common/GPU/OpenGL/GLCommon.h"
5
#include "Common/GPU/OpenGL/GLDebugLog.h"
6
#include "Common/GPU/OpenGL/GLFeatures.h"
7
#include "Common/GPU/OpenGL/DataFormatGL.h"
8
#include "Common/Math/math_util.h"
9
#include "Common/VR/PPSSPPVR.h"
10
11
#include "Common/Log.h"
12
#include "Common/LogReporting.h"
13
#include "Common/MemoryUtil.h"
14
#include "Common/StringUtils.h"
15
#include "Common/Data/Convert/SmallDataConvert.h"
16
17
#include "GLQueueRunner.h"
18
#include "GLRenderManager.h"
19
#include "DataFormatGL.h"
20
21
// These are the same value, alias for simplicity.
22
#if defined(GL_CLIP_DISTANCE0_EXT) && !defined(GL_CLIP_DISTANCE0)
23
#define GL_CLIP_DISTANCE0 GL_CLIP_DISTANCE0_EXT
24
#elif !defined(GL_CLIP_DISTANCE0)
25
#define GL_CLIP_DISTANCE0 0x3000
26
#endif
27
#ifndef GL_DEPTH_STENCIL_TEXTURE_MODE
28
#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA
29
#endif
30
#ifndef GL_STENCIL_INDEX
31
#define GL_STENCIL_INDEX 0x1901
32
#endif
33
34
static constexpr int TEXCACHE_NAME_CACHE_SIZE = 16;
35
36
#if PPSSPP_PLATFORM(IOS)
37
extern void bindDefaultFBO();
38
#endif
39
40
// Workaround for Retroarch. Simply declare
41
// extern GLuint g_defaultFBO;
42
// and set is as appropriate. Can adjust the variables in ext/native/base/display.h as
43
// appropriate.
44
GLuint g_defaultFBO = 0;
45
46
void GLQueueRunner::CreateDeviceObjects() {
47
CHECK_GL_ERROR_IF_DEBUG();
48
if (caps_.anisoSupported) {
49
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyLevel_);
50
} else {
51
maxAnisotropyLevel_ = 0.0f;
52
}
53
54
if (gl_extensions.ARB_vertex_array_object) {
55
glGenVertexArrays(1, &globalVAO_);
56
}
57
58
// An eternal optimist.
59
sawOutOfMemory_ = false;
60
61
// Populate some strings from the GL thread so they can be queried from thin3d.
62
// TODO: Merge with GLFeatures.cpp/h
63
auto populate = [&](int name) {
64
const GLubyte *value = glGetString(name);
65
if (!value)
66
glStrings_[name] = "?";
67
else
68
glStrings_[name] = (const char *)value;
69
};
70
populate(GL_VENDOR);
71
populate(GL_RENDERER);
72
populate(GL_VERSION);
73
populate(GL_SHADING_LANGUAGE_VERSION);
74
CHECK_GL_ERROR_IF_DEBUG();
75
76
#if !PPSSPP_ARCH(X86) // Doesn't work on AMD for some reason. See issue #17787
77
useDebugGroups_ = !gl_extensions.IsGLES && gl_extensions.VersionGEThan(4, 3);
78
#endif
79
}
80
81
void GLQueueRunner::DestroyDeviceObjects() {
82
CHECK_GL_ERROR_IF_DEBUG();
83
if (gl_extensions.ARB_vertex_array_object) {
84
glDeleteVertexArrays(1, &globalVAO_);
85
}
86
delete[] readbackBuffer_;
87
readbackBuffer_ = nullptr;
88
readbackBufferSize_ = 0;
89
CHECK_GL_ERROR_IF_DEBUG();
90
}
91
92
template <typename Getiv, typename GetLog>
93
static std::string GetInfoLog(GLuint name, Getiv getiv, GetLog getLog) {
94
GLint bufLength = 0;
95
getiv(name, GL_INFO_LOG_LENGTH, &bufLength);
96
if (bufLength <= 0)
97
bufLength = 2048;
98
99
std::string infoLog;
100
infoLog.resize(bufLength);
101
GLsizei len = 0;
102
getLog(name, (GLsizei)infoLog.size(), &len, &infoLog[0]);
103
if (len <= 0)
104
return "(unknown reason)";
105
106
infoLog.resize(len);
107
return infoLog;
108
}
109
110
void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLCalls) {
111
if (skipGLCalls) {
112
// Some bookkeeping still needs to be done.
113
for (size_t i = 0; i < steps.size(); i++) {
114
const GLRInitStep &step = steps[i];
115
switch (step.stepType) {
116
case GLRInitStepType::BUFFER_SUBDATA:
117
{
118
if (step.buffer_subdata.deleteData)
119
delete[] step.buffer_subdata.data;
120
break;
121
}
122
case GLRInitStepType::TEXTURE_IMAGE:
123
{
124
if (step.texture_image.allocType == GLRAllocType::ALIGNED) {
125
FreeAlignedMemory(step.texture_image.data);
126
} else if (step.texture_image.allocType == GLRAllocType::NEW) {
127
delete[] step.texture_image.data;
128
}
129
break;
130
}
131
case GLRInitStepType::CREATE_PROGRAM:
132
{
133
WARN_LOG(Log::G3D, "CREATE_PROGRAM found with skipGLCalls, not good");
134
break;
135
}
136
case GLRInitStepType::CREATE_SHADER:
137
{
138
WARN_LOG(Log::G3D, "CREATE_SHADER found with skipGLCalls, not good");
139
break;
140
}
141
default:
142
break;
143
}
144
}
145
return;
146
}
147
148
#if !defined(USING_GLES2)
149
if (useDebugGroups_)
150
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "InitSteps");
151
#endif
152
153
CHECK_GL_ERROR_IF_DEBUG();
154
glActiveTexture(GL_TEXTURE0);
155
GLuint boundTexture = (GLuint)-1;
156
bool allocatedTextures = false;
157
158
for (size_t i = 0; i < steps.size(); i++) {
159
const GLRInitStep &step = steps[i];
160
switch (step.stepType) {
161
case GLRInitStepType::CREATE_TEXTURE:
162
{
163
GLRTexture *tex = step.create_texture.texture;
164
glGenTextures(1, &tex->texture);
165
glBindTexture(tex->target, tex->texture);
166
boundTexture = tex->texture;
167
CHECK_GL_ERROR_IF_DEBUG();
168
break;
169
}
170
case GLRInitStepType::CREATE_BUFFER:
171
{
172
GLRBuffer *buffer = step.create_buffer.buffer;
173
glGenBuffers(1, &buffer->buffer_);
174
glBindBuffer(buffer->target_, buffer->buffer_);
175
glBufferData(buffer->target_, step.create_buffer.size, nullptr, step.create_buffer.usage);
176
CHECK_GL_ERROR_IF_DEBUG();
177
break;
178
}
179
case GLRInitStepType::BUFFER_SUBDATA:
180
{
181
GLRBuffer *buffer = step.buffer_subdata.buffer;
182
glBindBuffer(buffer->target_, buffer->buffer_);
183
glBufferSubData(buffer->target_, step.buffer_subdata.offset, step.buffer_subdata.size, step.buffer_subdata.data);
184
if (step.buffer_subdata.deleteData)
185
delete[] step.buffer_subdata.data;
186
CHECK_GL_ERROR_IF_DEBUG();
187
break;
188
}
189
case GLRInitStepType::CREATE_PROGRAM:
190
{
191
CHECK_GL_ERROR_IF_DEBUG();
192
GLRProgram *program = step.create_program.program;
193
program->program = glCreateProgram();
194
_assert_msg_(step.create_program.num_shaders > 0, "Can't create a program with zero shaders");
195
bool anyFailed = false;
196
for (int j = 0; j < step.create_program.num_shaders; j++) {
197
_dbg_assert_msg_(step.create_program.shaders[j]->shader, "Can't create a program with a null shader");
198
anyFailed = anyFailed || step.create_program.shaders[j]->failed;
199
glAttachShader(program->program, step.create_program.shaders[j]->shader);
200
}
201
202
for (auto iter : program->semantics_) {
203
glBindAttribLocation(program->program, iter.location, iter.attrib);
204
}
205
206
#if !defined(USING_GLES2)
207
if (step.create_program.support_dual_source) {
208
_dbg_assert_msg_(caps_.dualSourceBlend, "ARB/EXT_blend_func_extended required for dual src blend");
209
// Dual source alpha
210
glBindFragDataLocationIndexed(program->program, 0, 0, "fragColor0");
211
glBindFragDataLocationIndexed(program->program, 0, 1, "fragColor1");
212
} else if (gl_extensions.VersionGEThan(3, 0, 0)) {
213
glBindFragDataLocation(program->program, 0, "fragColor0");
214
}
215
#elif !PPSSPP_PLATFORM(IOS)
216
if (gl_extensions.GLES3 && step.create_program.support_dual_source) {
217
// For GLES2, we use gl_SecondaryFragColorEXT as fragColor1.
218
_dbg_assert_msg_(gl_extensions.EXT_blend_func_extended, "EXT_blend_func_extended required for dual src");
219
glBindFragDataLocationIndexedEXT(program->program, 0, 0, "fragColor0");
220
glBindFragDataLocationIndexedEXT(program->program, 0, 1, "fragColor1");
221
}
222
#endif
223
glLinkProgram(program->program);
224
225
GLint linkStatus = GL_FALSE;
226
glGetProgramiv(program->program, GL_LINK_STATUS, &linkStatus);
227
if (linkStatus != GL_TRUE) {
228
std::string infoLog = GetInfoLog(program->program, glGetProgramiv, glGetProgramInfoLog);
229
230
// TODO: Could be other than vs/fs. Also, we're assuming order here...
231
GLRShader *vs = step.create_program.shaders[0];
232
GLRShader *fs = step.create_program.num_shaders > 1 ? step.create_program.shaders[1] : nullptr;
233
std::string vsDesc = vs->desc + (vs->failed ? " (failed)" : "");
234
std::string fsDesc = fs ? (fs->desc + (fs->failed ? " (failed)" : "")) : "(none)";
235
const char *vsCode = vs->code.c_str();
236
const char *fsCode = fs ? fs->code.c_str() : "(none)";
237
if (!anyFailed)
238
Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", infoLog.c_str(), fsDesc.c_str(), fsCode, vsDesc.c_str(), vsCode);
239
240
ERROR_LOG(Log::G3D, "Could not link program:\n %s", infoLog.c_str());
241
ERROR_LOG(Log::G3D, "VS desc:\n%s", vsDesc.c_str());
242
ERROR_LOG(Log::G3D, "FS desc:\n%s", fsDesc.c_str());
243
ERROR_LOG(Log::G3D, "VS:\n%s\n", LineNumberString(vsCode).c_str());
244
ERROR_LOG(Log::G3D, "FS:\n%s\n", LineNumberString(fsCode).c_str());
245
246
#ifdef _WIN32
247
OutputDebugStringUTF8(infoLog.c_str());
248
if (vsCode)
249
OutputDebugStringUTF8(LineNumberString(vsCode).c_str());
250
if (fsCode)
251
OutputDebugStringUTF8(LineNumberString(fsCode).c_str());
252
#endif
253
CHECK_GL_ERROR_IF_DEBUG();
254
break;
255
}
256
257
glUseProgram(program->program);
258
259
// Query all the uniforms.
260
for (size_t j = 0; j < program->queries_.size(); j++) {
261
auto &query = program->queries_[j];
262
_dbg_assert_(query.name);
263
264
int location = glGetUniformLocation(program->program, query.name);
265
266
if (location < 0 && query.required) {
267
WARN_LOG(Log::G3D, "Required uniform query for '%s' failed", query.name);
268
}
269
*query.dest = location;
270
}
271
272
// Run initializers.
273
for (size_t j = 0; j < program->initialize_.size(); j++) {
274
auto &init = program->initialize_[j];
275
GLint uniform = *init.uniform;
276
if (uniform != -1) {
277
switch (init.type) {
278
case 0:
279
glUniform1i(uniform, init.value);
280
break;
281
}
282
}
283
}
284
CHECK_GL_ERROR_IF_DEBUG();
285
break;
286
}
287
case GLRInitStepType::CREATE_SHADER:
288
{
289
CHECK_GL_ERROR_IF_DEBUG();
290
GLuint shader = glCreateShader(step.create_shader.stage);
291
step.create_shader.shader->shader = shader;
292
const char *code = step.create_shader.code;
293
glShaderSource(shader, 1, &code, nullptr);
294
glCompileShader(shader);
295
GLint success = 0;
296
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
297
if (!success) {
298
std::string infoLog = GetInfoLog(shader, glGetShaderiv, glGetShaderInfoLog);
299
std::string errorString = StringFromFormat(
300
"Error in shader compilation for: %s\n"
301
"Info log: %s\n"
302
"Shader source:\n%s\n//END\n\n",
303
step.create_shader.shader->desc.c_str(),
304
infoLog.c_str(),
305
LineNumberString(code).c_str());
306
std::vector<std::string_view> lines;
307
SplitString(errorString, '\n', lines);
308
for (auto line : lines) {
309
ERROR_LOG(Log::G3D, "%.*s", (int)line.size(), line.data());
310
}
311
if (errorCallback_) {
312
std::string desc = StringFromFormat("Shader compilation failed: %s", step.create_shader.stage == GL_VERTEX_SHADER ? "vertex" : "fragment");
313
errorCallback_(desc.c_str(), errorString.c_str(), errorCallbackUserData_);
314
}
315
Reporting::ReportMessage("Error in shader compilation: info: %s\n%s\n%s", infoLog.c_str(), step.create_shader.shader->desc.c_str(), (const char *)code);
316
#ifdef SHADERLOG
317
OutputDebugStringUTF8(infoLog.c_str());
318
#endif
319
step.create_shader.shader->failed = true;
320
step.create_shader.shader->error = infoLog; // Hm, we never use this.
321
}
322
// Before we throw away the code, attach it to the shader for debugging.
323
step.create_shader.shader->code = code;
324
delete[] step.create_shader.code;
325
step.create_shader.shader->valid = true;
326
CHECK_GL_ERROR_IF_DEBUG();
327
break;
328
}
329
case GLRInitStepType::CREATE_INPUT_LAYOUT:
330
{
331
// GLRInputLayout *layout = step.create_input_layout.inputLayout;
332
// Nothing to do unless we want to create vertexbuffer objects (GL 4.5)
333
break;
334
}
335
case GLRInitStepType::CREATE_FRAMEBUFFER:
336
{
337
CHECK_GL_ERROR_IF_DEBUG();
338
boundTexture = (GLuint)-1;
339
InitCreateFramebuffer(step);
340
allocatedTextures = true;
341
CHECK_GL_ERROR_IF_DEBUG();
342
break;
343
}
344
case GLRInitStepType::TEXTURE_IMAGE:
345
{
346
GLRTexture *tex = step.texture_image.texture;
347
CHECK_GL_ERROR_IF_DEBUG();
348
if (boundTexture != tex->texture) {
349
glBindTexture(tex->target, tex->texture);
350
boundTexture = tex->texture;
351
}
352
if (!step.texture_image.data && step.texture_image.allocType != GLRAllocType::NONE)
353
_assert_msg_(false, "missing texture data");
354
355
// For things to show in RenderDoc, need to split into glTexImage2D(..., nullptr) and glTexSubImage.
356
357
int blockSize = 0;
358
bool bc = Draw::DataFormatIsBlockCompressed(step.texture_image.format, &blockSize);
359
360
GLenum internalFormat, format, type;
361
int alignment;
362
Thin3DFormatToGLFormatAndType(step.texture_image.format, internalFormat, format, type, alignment);
363
if (step.texture_image.depth == 1) {
364
if (bc) {
365
int dataSize = ((step.texture_image.width + 3) & ~3) * ((step.texture_image.height + 3) & ~3) * blockSize / 16;
366
glCompressedTexImage2D(tex->target, step.texture_image.level, internalFormat,
367
step.texture_image.width, step.texture_image.height, 0, dataSize, step.texture_image.data);
368
} else {
369
glTexImage2D(tex->target,
370
step.texture_image.level, internalFormat,
371
step.texture_image.width, step.texture_image.height, 0,
372
format, type, step.texture_image.data);
373
}
374
} else {
375
glTexImage3D(tex->target,
376
step.texture_image.level, internalFormat,
377
step.texture_image.width, step.texture_image.height, step.texture_image.depth, 0,
378
format, type, step.texture_image.data);
379
}
380
allocatedTextures = true;
381
if (step.texture_image.allocType == GLRAllocType::ALIGNED) {
382
FreeAlignedMemory(step.texture_image.data);
383
} else if (step.texture_image.allocType == GLRAllocType::NEW) {
384
delete[] step.texture_image.data;
385
}
386
CHECK_GL_ERROR_IF_DEBUG();
387
tex->wrapS = GL_CLAMP_TO_EDGE;
388
tex->wrapT = GL_CLAMP_TO_EDGE;
389
tex->magFilter = step.texture_image.linearFilter ? GL_LINEAR : GL_NEAREST;
390
tex->minFilter = step.texture_image.linearFilter ? GL_LINEAR : GL_NEAREST;
391
glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, tex->wrapS);
392
glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, tex->wrapT);
393
glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, tex->magFilter);
394
glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, tex->minFilter);
395
if (step.texture_image.depth > 1) {
396
glTexParameteri(tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
397
}
398
CHECK_GL_ERROR_IF_DEBUG();
399
break;
400
}
401
case GLRInitStepType::TEXTURE_FINALIZE:
402
{
403
CHECK_GL_ERROR_IF_DEBUG();
404
GLRTexture *tex = step.texture_finalize.texture;
405
if (boundTexture != tex->texture) {
406
glBindTexture(tex->target, tex->texture);
407
boundTexture = tex->texture;
408
}
409
if ((!gl_extensions.IsGLES || gl_extensions.GLES3) && step.texture_finalize.loadedLevels > 1) {
410
glTexParameteri(tex->target, GL_TEXTURE_MAX_LEVEL, step.texture_finalize.loadedLevels - 1);
411
}
412
tex->maxLod = (float)step.texture_finalize.loadedLevels - 1;
413
if (step.texture_finalize.genMips) {
414
glGenerateMipmap(tex->target);
415
}
416
CHECK_GL_ERROR_IF_DEBUG();
417
break;
418
}
419
default:
420
CHECK_GL_ERROR_IF_DEBUG();
421
_assert_msg_(false, "Bad GLRInitStepType: %d", (int)step.stepType);
422
break;
423
}
424
}
425
CHECK_GL_ERROR_IF_DEBUG();
426
427
// TODO: Use GL_KHR_no_error or a debug callback, where supported?
428
if (false && allocatedTextures) {
429
// Users may use replacements or scaling, with high render resolutions, and run out of VRAM.
430
// This detects that, rather than looking like PPSSPP is broken.
431
// Calling glGetError() isn't great, but at the end of init, only after creating textures, shouldn't be too bad...
432
GLenum err = glGetError();
433
if (err == GL_OUT_OF_MEMORY) {
434
WARN_LOG_REPORT(Log::G3D, "GL ran out of GPU memory; switching to low memory mode");
435
sawOutOfMemory_ = true;
436
} else if (err != GL_NO_ERROR) {
437
// We checked the err anyway, might as well log if there is one.
438
std::string errorString = GLEnumToString(err);
439
WARN_LOG(Log::G3D, "Got an error after init: %08x (%s)", err, errorString.c_str());
440
if (errorCallback_) {
441
errorCallback_("GL frame init error", errorString.c_str(), errorCallbackUserData_);
442
}
443
}
444
}
445
446
glBindBuffer(GL_ARRAY_BUFFER, 0);
447
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
448
449
#if !defined(USING_GLES2)
450
if (useDebugGroups_)
451
glPopDebugGroup();
452
#endif
453
}
454
455
void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) {
456
GLRFramebuffer *fbo = step.create_framebuffer.framebuffer;
457
458
#ifndef USING_GLES2
459
if (!gl_extensions.ARB_framebuffer_object && gl_extensions.EXT_framebuffer_object) {
460
fbo_ext_create(step);
461
} else if (!gl_extensions.ARB_framebuffer_object && !gl_extensions.IsGLES) {
462
return;
463
}
464
// If GLES2, we have basic FBO support and can just proceed.
465
#endif
466
CHECK_GL_ERROR_IF_DEBUG();
467
468
auto initFBOTexture = [&](GLRTexture &tex, GLint internalFormat, GLenum format, GLenum type, bool linear) {
469
glGenTextures(1, &tex.texture);
470
tex.target = GL_TEXTURE_2D;
471
tex.maxLod = 0.0f;
472
473
// Create the surfaces.
474
glBindTexture(GL_TEXTURE_2D, tex.texture);
475
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, fbo->width, fbo->height, 0, format, type, nullptr);
476
477
tex.wrapS = GL_CLAMP_TO_EDGE;
478
tex.wrapT = GL_CLAMP_TO_EDGE;
479
tex.magFilter = linear ? GL_LINEAR : GL_NEAREST;
480
tex.minFilter = linear ? GL_LINEAR : GL_NEAREST;
481
482
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex.wrapS);
483
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex.wrapT);
484
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex.magFilter);
485
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex.minFilter);
486
if (!gl_extensions.IsGLES || gl_extensions.GLES3) {
487
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
488
}
489
};
490
491
// Color texture is same everywhere
492
glGenFramebuffers(1, &fbo->handle);
493
initFBOTexture(fbo->color_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true);
494
495
retry_depth:
496
if (!fbo->z_stencil_) {
497
INFO_LOG(Log::G3D, "Creating %d x %d FBO using no depth", fbo->width, fbo->height);
498
499
fbo->z_stencil_buffer = 0;
500
fbo->stencil_buffer = 0;
501
fbo->z_buffer = 0;
502
503
// Bind it all together
504
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
505
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0);
506
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
507
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
508
} else if (gl_extensions.IsGLES) {
509
if (gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3)) {
510
INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height);
511
fbo->z_stencil_buffer = 0;
512
fbo->stencil_buffer = 0;
513
fbo->z_buffer = 0;
514
515
if (gl_extensions.GLES3) {
516
initFBOTexture(fbo->z_stencil_texture, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false);
517
} else {
518
initFBOTexture(fbo->z_stencil_texture, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false);
519
}
520
521
// Bind it all together
522
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
523
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0);
524
if (gl_extensions.GLES3) {
525
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0);
526
} else {
527
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0);
528
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0);
529
}
530
} else if (gl_extensions.OES_packed_depth_stencil) {
531
INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8", fbo->width, fbo->height);
532
// Standard method
533
fbo->stencil_buffer = 0;
534
fbo->z_buffer = 0;
535
// 24-bit Z, 8-bit stencil combined
536
glGenRenderbuffers(1, &fbo->z_stencil_buffer);
537
glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_stencil_buffer);
538
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, fbo->width, fbo->height);
539
540
// Bind it all together
541
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
542
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0);
543
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
544
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
545
} else {
546
INFO_LOG(Log::G3D, "Creating %d x %d FBO using separate stencil", fbo->width, fbo->height);
547
// TEGRA
548
fbo->z_stencil_buffer = 0;
549
// 16/24-bit Z, separate 8-bit stencil
550
glGenRenderbuffers(1, &fbo->z_buffer);
551
glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_buffer);
552
// Don't forget to make sure fbo_standard_z_depth() matches.
553
glRenderbufferStorage(GL_RENDERBUFFER, gl_extensions.OES_depth24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, fbo->width, fbo->height);
554
555
// 8-bit stencil buffer
556
glGenRenderbuffers(1, &fbo->stencil_buffer);
557
glBindRenderbuffer(GL_RENDERBUFFER, fbo->stencil_buffer);
558
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fbo->width, fbo->height);
559
560
// Bind it all together
561
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
562
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0);
563
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_buffer);
564
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer);
565
}
566
} else if (gl_extensions.VersionGEThan(3, 0)) {
567
INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height);
568
fbo->z_stencil_buffer = 0;
569
fbo->stencil_buffer = 0;
570
fbo->z_buffer = 0;
571
572
initFBOTexture(fbo->z_stencil_texture, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false);
573
574
// Bind it all together
575
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
576
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0);
577
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0);
578
} else {
579
fbo->stencil_buffer = 0;
580
fbo->z_buffer = 0;
581
// 24-bit Z, 8-bit stencil
582
glGenRenderbuffers(1, &fbo->z_stencil_buffer);
583
glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_stencil_buffer);
584
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fbo->width, fbo->height);
585
586
// Bind it all together
587
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
588
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0);
589
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
590
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
591
}
592
593
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
594
if (status != GL_FRAMEBUFFER_COMPLETE && !fbo->z_buffer) {
595
CHECK_GL_ERROR_IF_DEBUG();
596
// Uh oh, maybe we need a z/stencil. Platforms sometimes, right?
597
fbo->z_stencil_ = true;
598
goto retry_depth;
599
}
600
601
switch (status) {
602
case GL_FRAMEBUFFER_COMPLETE:
603
// INFO_LOG(Log::G3D, "Framebuffer verified complete.");
604
break;
605
case GL_FRAMEBUFFER_UNSUPPORTED:
606
ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_UNSUPPORTED");
607
break;
608
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
609
ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
610
break;
611
default:
612
_assert_msg_(false, "Other framebuffer error: %d", status);
613
break;
614
}
615
616
// Unbind state we don't need
617
glBindRenderbuffer(GL_RENDERBUFFER, 0);
618
glBindTexture(GL_TEXTURE_2D, 0);
619
CHECK_GL_ERROR_IF_DEBUG();
620
621
currentDrawHandle_ = fbo->handle;
622
currentReadHandle_ = fbo->handle;
623
}
624
625
void GLQueueRunner::RunSteps(const std::vector<GLRStep *> &steps, GLFrameData &frameData, bool skipGLCalls, bool keepSteps, bool useVR) {
626
if (skipGLCalls) {
627
if (keepSteps) {
628
return;
629
}
630
// Dry run
631
for (size_t i = 0; i < steps.size(); i++) {
632
const GLRStep &step = *steps[i];
633
switch (step.stepType) {
634
case GLRStepType::RENDER:
635
for (const auto &c : step.commands) {
636
switch (c.cmd) {
637
case GLRRenderCommand::TEXTURE_SUBIMAGE:
638
if (c.texture_subimage.data) {
639
if (c.texture_subimage.allocType == GLRAllocType::ALIGNED) {
640
FreeAlignedMemory(c.texture_subimage.data);
641
} else if (c.texture_subimage.allocType == GLRAllocType::NEW) {
642
delete[] c.texture_subimage.data;
643
}
644
}
645
break;
646
default:
647
break;
648
}
649
}
650
break;
651
default:
652
break;
653
}
654
delete steps[i];
655
}
656
return;
657
}
658
659
size_t totalRenderCount = 0;
660
for (auto &step : steps) {
661
if (step->stepType == GLRStepType::RENDER) {
662
// Skip empty render steps.
663
if (step->commands.empty()) {
664
step->stepType = GLRStepType::RENDER_SKIP;
665
continue;
666
}
667
totalRenderCount++;
668
}
669
}
670
671
CHECK_GL_ERROR_IF_DEBUG();
672
size_t renderCount = 0;
673
for (size_t i = 0; i < steps.size(); i++) {
674
GLRStep &step = *steps[i];
675
676
#if !defined(USING_GLES2)
677
if (useDebugGroups_)
678
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, (GLuint)i + 10000, -1, step.tag);
679
#endif
680
681
switch (step.stepType) {
682
case GLRStepType::RENDER:
683
renderCount++;
684
if (IsVREnabled()) {
685
PreprocessStepVR(&step);
686
PerformRenderPass(step, renderCount == 1, renderCount == totalRenderCount, frameData.profile);
687
} else {
688
PerformRenderPass(step, renderCount == 1, renderCount == totalRenderCount, frameData.profile);
689
}
690
break;
691
case GLRStepType::COPY:
692
PerformCopy(step);
693
break;
694
case GLRStepType::BLIT:
695
PerformBlit(step);
696
break;
697
case GLRStepType::READBACK:
698
PerformReadback(step);
699
break;
700
case GLRStepType::READBACK_IMAGE:
701
PerformReadbackImage(step);
702
break;
703
case GLRStepType::RENDER_SKIP:
704
break;
705
default:
706
Crash();
707
break;
708
}
709
710
#if !defined(USING_GLES2)
711
if (useDebugGroups_)
712
glPopDebugGroup();
713
#endif
714
if (frameData.profile.enabled) {
715
frameData.profile.passesString += StepToString(step);
716
}
717
if (!keepSteps) {
718
delete steps[i];
719
}
720
}
721
722
CHECK_GL_ERROR_IF_DEBUG();
723
}
724
725
void GLQueueRunner::PerformBlit(const GLRStep &step) {
726
CHECK_GL_ERROR_IF_DEBUG();
727
// Without FBO_ARB / GLES3, this will collide with bind_for_read, but there's nothing
728
// in ES 2.0 that actually separate them anyway of course, so doesn't matter.
729
fbo_bind_fb_target(false, step.blit.dst->handle);
730
fbo_bind_fb_target(true, step.blit.src->handle);
731
732
int srcX1 = step.blit.srcRect.x;
733
int srcY1 = step.blit.srcRect.y;
734
int srcX2 = step.blit.srcRect.x + step.blit.srcRect.w;
735
int srcY2 = step.blit.srcRect.y + step.blit.srcRect.h;
736
int dstX1 = step.blit.dstRect.x;
737
int dstY1 = step.blit.dstRect.y;
738
int dstX2 = step.blit.dstRect.x + step.blit.dstRect.w;
739
int dstY2 = step.blit.dstRect.y + step.blit.dstRect.h;
740
741
if (gl_extensions.GLES3 || gl_extensions.ARB_framebuffer_object) {
742
glBlitFramebuffer(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, step.blit.aspectMask, step.blit.filter ? GL_LINEAR : GL_NEAREST);
743
CHECK_GL_ERROR_IF_DEBUG();
744
#if defined(USING_GLES2) && defined(__ANDROID__) // We only support this extension on Android, it's not even available on PC.
745
} else if (gl_extensions.NV_framebuffer_blit) {
746
glBlitFramebufferNV(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, step.blit.aspectMask, step.blit.filter ? GL_LINEAR : GL_NEAREST);
747
CHECK_GL_ERROR_IF_DEBUG();
748
#endif // defined(USING_GLES2) && defined(__ANDROID__)
749
} else {
750
ERROR_LOG(Log::G3D, "GLQueueRunner: Tried to blit without the capability");
751
}
752
}
753
754
static void EnableDisableVertexArrays(uint32_t prevAttr, uint32_t newAttr) {
755
int enable = (~prevAttr) & newAttr;
756
int disable = prevAttr & (~newAttr);
757
for (int i = 0; i < 7; i++) { // SEM_MAX
758
if (enable & (1 << i)) {
759
glEnableVertexAttribArray(i);
760
}
761
if (disable & (1 << i)) {
762
glDisableVertexAttribArray(i);
763
}
764
}
765
}
766
767
void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last, GLQueueProfileContext &profile) {
768
CHECK_GL_ERROR_IF_DEBUG();
769
770
PerformBindFramebufferAsRenderTarget(step);
771
772
if (first) {
773
glDisable(GL_DEPTH_TEST);
774
glDisable(GL_STENCIL_TEST);
775
glDisable(GL_BLEND);
776
glDisable(GL_CULL_FACE);
777
glDisable(GL_DITHER);
778
glEnable(GL_SCISSOR_TEST);
779
#ifndef USING_GLES2
780
if (!gl_extensions.IsGLES) {
781
glDisable(GL_COLOR_LOGIC_OP);
782
}
783
#endif
784
if (gl_extensions.ARB_vertex_array_object) {
785
glBindVertexArray(globalVAO_);
786
}
787
}
788
789
GLRProgram *curProgram = nullptr;
790
int activeSlot = -1;
791
792
// State filtering tracking.
793
int attrMask = 0;
794
int colorMask = -1;
795
int depthMask = -1;
796
int depthFunc = -1;
797
GLuint curArrayBuffer = (GLuint)0;
798
GLuint curElemArrayBuffer = (GLuint)0;
799
bool depthEnabled = false;
800
bool stencilEnabled = false;
801
bool blendEnabled = false;
802
bool cullEnabled = false;
803
bool ditherEnabled = false;
804
bool depthClampEnabled = false;
805
#ifndef USING_GLES2
806
int logicOp = -1;
807
bool logicEnabled = false;
808
#endif
809
bool clipDistanceEnabled[8]{};
810
GLuint blendEqColor = (GLuint)-1;
811
GLuint blendEqAlpha = (GLuint)-1;
812
GLenum blendSrcColor = (GLenum)-1;
813
GLenum blendDstColor = (GLenum)-1;
814
GLenum blendSrcAlpha = (GLenum)-1;
815
GLenum blendDstAlpha = (GLenum)-1;
816
817
GLuint stencilWriteMask = (GLuint)-1;
818
GLenum stencilFunc = (GLenum)-1;
819
GLuint stencilRef = (GLuint)-1;
820
GLuint stencilCompareMask = (GLuint)-1;
821
GLenum stencilSFail = (GLenum)-1;
822
GLenum stencilZFail = (GLenum)-1;
823
GLenum stencilPass = (GLenum)-1;
824
GLenum frontFace = (GLenum)-1;
825
GLenum cullFace = (GLenum)-1;
826
GLRTexture *curTex[MAX_GL_TEXTURE_SLOTS]{};
827
828
GLRViewport viewport = {
829
-1000000000.0f,
830
-1000000000.0f,
831
-1000000000.0f,
832
-1000000000.0f,
833
-1000000000.0f,
834
-1000000000.0f,
835
};
836
837
GLRect2D scissorRc = { -1, -1, -1, -1 };
838
839
CHECK_GL_ERROR_IF_DEBUG();
840
auto &commands = step.commands;
841
for (const auto &c : commands) {
842
#ifdef _DEBUG
843
if (profile.enabled) {
844
if ((size_t)c.cmd < ARRAY_SIZE(profile.commandCounts)) {
845
profile.commandCounts[(size_t)c.cmd]++;
846
}
847
}
848
#endif
849
switch (c.cmd) {
850
case GLRRenderCommand::DEPTH:
851
if (c.depth.enabled) {
852
if (!depthEnabled) {
853
glEnable(GL_DEPTH_TEST);
854
depthEnabled = true;
855
}
856
if (c.depth.write != depthMask) {
857
glDepthMask(c.depth.write);
858
depthMask = c.depth.write;
859
}
860
if (c.depth.func != depthFunc) {
861
glDepthFunc(c.depth.func);
862
depthFunc = c.depth.func;
863
}
864
} else if (/* !c.depth.enabled && */ depthEnabled) {
865
glDisable(GL_DEPTH_TEST);
866
depthEnabled = false;
867
}
868
break;
869
case GLRRenderCommand::STENCIL:
870
if (c.stencil.enabled) {
871
if (!stencilEnabled) {
872
glEnable(GL_STENCIL_TEST);
873
stencilEnabled = true;
874
}
875
if (c.stencil.func != stencilFunc || c.stencil.ref != stencilRef || c.stencil.compareMask != stencilCompareMask) {
876
glStencilFunc(c.stencil.func, c.stencil.ref, c.stencil.compareMask);
877
stencilFunc = c.stencil.func;
878
stencilRef = c.stencil.ref;
879
stencilCompareMask = c.stencil.compareMask;
880
}
881
if (c.stencil.sFail != stencilSFail || c.stencil.zFail != stencilZFail || c.stencil.pass != stencilPass) {
882
glStencilOp(c.stencil.sFail, c.stencil.zFail, c.stencil.pass);
883
stencilSFail = c.stencil.sFail;
884
stencilZFail = c.stencil.zFail;
885
stencilPass = c.stencil.pass;
886
}
887
if (c.stencil.writeMask != stencilWriteMask) {
888
glStencilMask(c.stencil.writeMask);
889
stencilWriteMask = c.stencil.writeMask;
890
}
891
} else if (/* !c.stencilFunc.enabled && */stencilEnabled) {
892
glDisable(GL_STENCIL_TEST);
893
stencilEnabled = false;
894
}
895
CHECK_GL_ERROR_IF_DEBUG();
896
break;
897
case GLRRenderCommand::BLEND:
898
if (c.blend.enabled) {
899
if (!blendEnabled) {
900
glEnable(GL_BLEND);
901
blendEnabled = true;
902
}
903
if (blendEqColor != c.blend.funcColor || blendEqAlpha != c.blend.funcAlpha) {
904
glBlendEquationSeparate(c.blend.funcColor, c.blend.funcAlpha);
905
blendEqColor = c.blend.funcColor;
906
blendEqAlpha = c.blend.funcAlpha;
907
}
908
if (blendSrcColor != c.blend.srcColor || blendDstColor != c.blend.dstColor || blendSrcAlpha != c.blend.srcAlpha || blendDstAlpha != c.blend.dstAlpha) {
909
glBlendFuncSeparate(c.blend.srcColor, c.blend.dstColor, c.blend.srcAlpha, c.blend.dstAlpha);
910
blendSrcColor = c.blend.srcColor;
911
blendDstColor = c.blend.dstColor;
912
blendSrcAlpha = c.blend.srcAlpha;
913
blendDstAlpha = c.blend.dstAlpha;
914
}
915
} else if (/* !c.blend.enabled && */ blendEnabled) {
916
glDisable(GL_BLEND);
917
blendEnabled = false;
918
}
919
if (c.blend.mask != colorMask) {
920
glColorMask(c.blend.mask & 1, (c.blend.mask >> 1) & 1, (c.blend.mask >> 2) & 1, (c.blend.mask >> 3) & 1);
921
colorMask = c.blend.mask;
922
}
923
CHECK_GL_ERROR_IF_DEBUG();
924
break;
925
case GLRRenderCommand::LOGICOP:
926
#ifndef USING_GLES2
927
if (c.logic.enabled) {
928
if (!logicEnabled) {
929
glEnable(GL_COLOR_LOGIC_OP);
930
logicEnabled = true;
931
}
932
if (logicOp != c.logic.logicOp) {
933
glLogicOp(c.logic.logicOp);
934
}
935
} else if (/* !c.logic.enabled && */ logicEnabled) {
936
glDisable(GL_COLOR_LOGIC_OP);
937
logicEnabled = false;
938
}
939
#endif
940
CHECK_GL_ERROR_IF_DEBUG();
941
break;
942
case GLRRenderCommand::CLEAR:
943
// Scissor test is on, and should be on after leaving this case. If we disable it,
944
// we re-enable it at the end.
945
if (c.clear.scissorW == 0) {
946
glDisable(GL_SCISSOR_TEST);
947
} else {
948
glScissor(c.clear.scissorX, c.clear.scissorY, c.clear.scissorW, c.clear.scissorH);
949
}
950
if (c.clear.colorMask != colorMask) {
951
glColorMask(c.clear.colorMask & 1, (c.clear.colorMask >> 1) & 1, (c.clear.colorMask >> 2) & 1, (c.clear.colorMask >> 3) & 1);
952
}
953
if (c.clear.clearMask & GL_COLOR_BUFFER_BIT) {
954
float color[4];
955
Uint8x4ToFloat4(color, c.clear.clearColor);
956
glClearColor(color[0], color[1], color[2], color[3]);
957
}
958
if (c.clear.clearMask & GL_DEPTH_BUFFER_BIT) {
959
#if defined(USING_GLES2)
960
glClearDepthf(c.clear.clearZ);
961
#else
962
if (gl_extensions.IsGLES) {
963
glClearDepthf(c.clear.clearZ);
964
} else {
965
glClearDepth(c.clear.clearZ);
966
}
967
#endif
968
}
969
if (c.clear.clearMask & GL_STENCIL_BUFFER_BIT) {
970
glClearStencil(c.clear.clearStencil);
971
}
972
glClear(c.clear.clearMask);
973
// Restore the color mask if it was different.
974
if (c.clear.colorMask != colorMask) {
975
glColorMask(colorMask & 1, (colorMask >> 1) & 1, (colorMask >> 2) & 1, (colorMask >> 3) & 1);
976
}
977
if (c.clear.scissorW == 0) {
978
glEnable(GL_SCISSOR_TEST);
979
}
980
CHECK_GL_ERROR_IF_DEBUG();
981
break;
982
case GLRRenderCommand::BLENDCOLOR:
983
glBlendColor(c.blendColor.color[0], c.blendColor.color[1], c.blendColor.color[2], c.blendColor.color[3]);
984
break;
985
case GLRRenderCommand::VIEWPORT:
986
{
987
float y = c.viewport.vp.y;
988
if (!curFB_)
989
y = curFBHeight_ - y - c.viewport.vp.h;
990
991
// TODO: Support FP viewports through glViewportArrays
992
if (viewport.x != c.viewport.vp.x || viewport.y != y || viewport.w != c.viewport.vp.w || viewport.h != c.viewport.vp.h) {
993
glViewport((GLint)c.viewport.vp.x, (GLint)y, (GLsizei)c.viewport.vp.w, (GLsizei)c.viewport.vp.h);
994
viewport.x = c.viewport.vp.x;
995
viewport.y = y;
996
viewport.w = c.viewport.vp.w;
997
viewport.h = c.viewport.vp.h;
998
}
999
1000
if (viewport.minZ != c.viewport.vp.minZ || viewport.maxZ != c.viewport.vp.maxZ) {
1001
viewport.minZ = c.viewport.vp.minZ;
1002
viewport.maxZ = c.viewport.vp.maxZ;
1003
#if !defined(USING_GLES2)
1004
if (gl_extensions.IsGLES) {
1005
glDepthRangef(c.viewport.vp.minZ, c.viewport.vp.maxZ);
1006
} else {
1007
glDepthRange(c.viewport.vp.minZ, c.viewport.vp.maxZ);
1008
}
1009
#else
1010
glDepthRangef(c.viewport.vp.minZ, c.viewport.vp.maxZ);
1011
#endif
1012
}
1013
CHECK_GL_ERROR_IF_DEBUG();
1014
break;
1015
}
1016
case GLRRenderCommand::SCISSOR:
1017
{
1018
int y = c.scissor.rc.y;
1019
if (!curFB_)
1020
y = curFBHeight_ - y - c.scissor.rc.h;
1021
if (scissorRc.x != c.scissor.rc.x || scissorRc.y != y || scissorRc.w != c.scissor.rc.w || scissorRc.h != c.scissor.rc.h) {
1022
glScissor(c.scissor.rc.x, y, c.scissor.rc.w, c.scissor.rc.h);
1023
scissorRc.x = c.scissor.rc.x;
1024
scissorRc.y = y;
1025
scissorRc.w = c.scissor.rc.w;
1026
scissorRc.h = c.scissor.rc.h;
1027
}
1028
CHECK_GL_ERROR_IF_DEBUG();
1029
break;
1030
}
1031
case GLRRenderCommand::UNIFORM4F:
1032
{
1033
_dbg_assert_(curProgram);
1034
int loc = c.uniform4.loc ? *c.uniform4.loc : -1;
1035
if (c.uniform4.name) {
1036
loc = curProgram->GetUniformLoc(c.uniform4.name);
1037
}
1038
if (loc >= 0) {
1039
_dbg_assert_(c.uniform4.count >=1 && c.uniform4.count <=4);
1040
switch (c.uniform4.count) {
1041
case 1: glUniform1f(loc, c.uniform4.v[0]); break;
1042
case 2: glUniform2fv(loc, 1, c.uniform4.v); break;
1043
case 3: glUniform3fv(loc, 1, c.uniform4.v); break;
1044
case 4: glUniform4fv(loc, 1, c.uniform4.v); break;
1045
}
1046
}
1047
CHECK_GL_ERROR_IF_DEBUG();
1048
break;
1049
}
1050
case GLRRenderCommand::UNIFORM4UI:
1051
{
1052
_dbg_assert_(curProgram);
1053
int loc = c.uniform4.loc ? *c.uniform4.loc : -1;
1054
if (c.uniform4.name) {
1055
loc = curProgram->GetUniformLoc(c.uniform4.name);
1056
}
1057
if (loc >= 0) {
1058
_dbg_assert_(c.uniform4.count >=1 && c.uniform4.count <=4);
1059
switch (c.uniform4.count) {
1060
case 1: glUniform1uiv(loc, 1, (GLuint *)c.uniform4.v); break;
1061
case 2: glUniform2uiv(loc, 1, (GLuint *)c.uniform4.v); break;
1062
case 3: glUniform3uiv(loc, 1, (GLuint *)c.uniform4.v); break;
1063
case 4: glUniform4uiv(loc, 1, (GLuint *)c.uniform4.v); break;
1064
}
1065
}
1066
CHECK_GL_ERROR_IF_DEBUG();
1067
break;
1068
}
1069
case GLRRenderCommand::UNIFORM4I:
1070
{
1071
_dbg_assert_(curProgram);
1072
int loc = c.uniform4.loc ? *c.uniform4.loc : -1;
1073
if (c.uniform4.name) {
1074
loc = curProgram->GetUniformLoc(c.uniform4.name);
1075
}
1076
if (loc >= 0) {
1077
_dbg_assert_(c.uniform4.count >=1 && c.uniform4.count <=4);
1078
switch (c.uniform4.count) {
1079
case 1: glUniform1iv(loc, 1, (GLint *)c.uniform4.v); break;
1080
case 2: glUniform2iv(loc, 1, (GLint *)c.uniform4.v); break;
1081
case 3: glUniform3iv(loc, 1, (GLint *)c.uniform4.v); break;
1082
case 4: glUniform4iv(loc, 1, (GLint *)c.uniform4.v); break;
1083
}
1084
}
1085
CHECK_GL_ERROR_IF_DEBUG();
1086
break;
1087
}
1088
case GLRRenderCommand::UNIFORMSTEREOMATRIX:
1089
{
1090
_dbg_assert_(curProgram);
1091
int loc = c.uniformStereoMatrix4.loc ? *c.uniformStereoMatrix4.loc : -1;
1092
if (c.uniformStereoMatrix4.name) {
1093
loc = curProgram->GetUniformLoc(c.uniformStereoMatrix4.name);
1094
}
1095
if (loc >= 0) {
1096
if (GetVRFBOIndex() == 0) {
1097
glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData);
1098
} else {
1099
glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData + 16);
1100
}
1101
}
1102
if (GetVRFBOIndex() == 1 || GetVRPassesCount() == 1) {
1103
// Only delete the data if we're rendering the only or the second eye.
1104
// If we delete during the first eye, we get a use-after-free or double delete.
1105
delete[] c.uniformStereoMatrix4.mData;
1106
}
1107
CHECK_GL_ERROR_IF_DEBUG();
1108
break;
1109
}
1110
case GLRRenderCommand::UNIFORMMATRIX:
1111
{
1112
_dbg_assert_(curProgram);
1113
int loc = c.uniformMatrix4.loc ? *c.uniformMatrix4.loc : -1;
1114
if (c.uniformMatrix4.name) {
1115
loc = curProgram->GetUniformLoc(c.uniformMatrix4.name);
1116
}
1117
if (loc >= 0) {
1118
glUniformMatrix4fv(loc, 1, false, c.uniformMatrix4.m);
1119
}
1120
CHECK_GL_ERROR_IF_DEBUG();
1121
break;
1122
}
1123
case GLRRenderCommand::BINDTEXTURE:
1124
{
1125
GLint slot = c.texture.slot;
1126
if (slot != activeSlot) {
1127
glActiveTexture(GL_TEXTURE0 + slot);
1128
activeSlot = slot;
1129
}
1130
if (c.texture.texture) {
1131
if (curTex[slot] != c.texture.texture) {
1132
glBindTexture(c.texture.texture->target, c.texture.texture->texture);
1133
curTex[slot] = c.texture.texture;
1134
}
1135
} else {
1136
glBindTexture(GL_TEXTURE_2D, 0); // Which target? Well we only use this one anyway...
1137
curTex[slot] = nullptr;
1138
}
1139
CHECK_GL_ERROR_IF_DEBUG();
1140
break;
1141
}
1142
case GLRRenderCommand::BIND_FB_TEXTURE:
1143
{
1144
GLint slot = c.bind_fb_texture.slot;
1145
if (slot != activeSlot) {
1146
glActiveTexture(GL_TEXTURE0 + slot);
1147
activeSlot = slot;
1148
}
1149
if (c.bind_fb_texture.aspect == GL_COLOR_BUFFER_BIT) {
1150
if (curTex[slot] != &c.bind_fb_texture.framebuffer->color_texture) {
1151
glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->color_texture.texture);
1152
curTex[slot] = &c.bind_fb_texture.framebuffer->color_texture;
1153
}
1154
} else if (c.bind_fb_texture.aspect == GL_DEPTH_BUFFER_BIT) {
1155
if (curTex[slot] != &c.bind_fb_texture.framebuffer->z_stencil_texture) {
1156
glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->z_stencil_texture.texture);
1157
curTex[slot] = &c.bind_fb_texture.framebuffer->z_stencil_texture;
1158
}
1159
// This should be uncommon, so always set the mode.
1160
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
1161
} else if (c.bind_fb_texture.aspect == GL_STENCIL_BUFFER_BIT) {
1162
if (curTex[slot] != &c.bind_fb_texture.framebuffer->z_stencil_texture) {
1163
glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->z_stencil_texture.texture);
1164
curTex[slot] = &c.bind_fb_texture.framebuffer->z_stencil_texture;
1165
}
1166
// This should be uncommon, so always set the mode.
1167
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
1168
} else {
1169
curTex[slot] = nullptr;
1170
}
1171
CHECK_GL_ERROR_IF_DEBUG();
1172
break;
1173
}
1174
case GLRRenderCommand::BINDPROGRAM:
1175
{
1176
if (curProgram != c.program.program) {
1177
glUseProgram(c.program.program->program);
1178
curProgram = c.program.program;
1179
1180
for (size_t i = 0; i < ARRAY_SIZE(clipDistanceEnabled); ++i) {
1181
if (c.program.program->use_clip_distance[i] == clipDistanceEnabled[i])
1182
continue;
1183
1184
if (c.program.program->use_clip_distance[i])
1185
glEnable(GL_CLIP_DISTANCE0 + (GLenum)i);
1186
else
1187
glDisable(GL_CLIP_DISTANCE0 + (GLenum)i);
1188
clipDistanceEnabled[i] = c.program.program->use_clip_distance[i];
1189
}
1190
}
1191
CHECK_GL_ERROR_IF_DEBUG();
1192
break;
1193
}
1194
case GLRRenderCommand::DRAW:
1195
{
1196
GLRInputLayout *layout = c.draw.inputLayout;
1197
GLuint buf = c.draw.vertexBuffer->buffer_;
1198
_dbg_assert_(!c.draw.vertexBuffer->Mapped());
1199
if (buf != curArrayBuffer) {
1200
glBindBuffer(GL_ARRAY_BUFFER, buf);
1201
curArrayBuffer = buf;
1202
}
1203
if (attrMask != layout->semanticsMask_) {
1204
EnableDisableVertexArrays(attrMask, layout->semanticsMask_);
1205
attrMask = layout->semanticsMask_;
1206
}
1207
for (size_t i = 0; i < layout->entries.size(); i++) {
1208
auto &entry = layout->entries[i];
1209
glVertexAttribPointer(entry.location, entry.count, entry.type, entry.normalized, layout->stride, (const void *)(c.draw.vertexOffset + entry.offset));
1210
}
1211
if (c.draw.indexBuffer) {
1212
GLuint buf = c.draw.indexBuffer->buffer_;
1213
_dbg_assert_(!c.draw.indexBuffer->Mapped());
1214
if (buf != curElemArrayBuffer) {
1215
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
1216
curElemArrayBuffer = buf;
1217
}
1218
if (c.draw.instances == 1) {
1219
glDrawElements(c.draw.mode, c.draw.count, c.draw.indexType, (void *)(intptr_t)c.draw.indexOffset);
1220
} else {
1221
glDrawElementsInstanced(c.draw.mode, c.draw.count, c.draw.indexType, (void *)(intptr_t)c.draw.indexOffset, c.draw.instances);
1222
}
1223
} else {
1224
glDrawArrays(c.draw.mode, c.draw.first, c.draw.count);
1225
}
1226
CHECK_GL_ERROR_IF_DEBUG();
1227
break;
1228
}
1229
case GLRRenderCommand::GENMIPS:
1230
// TODO: Should we include the texture handle in the command?
1231
// Also, should this not be an init command?
1232
glGenerateMipmap(GL_TEXTURE_2D);
1233
CHECK_GL_ERROR_IF_DEBUG();
1234
break;
1235
case GLRRenderCommand::TEXTURESAMPLER:
1236
{
1237
CHECK_GL_ERROR_IF_DEBUG();
1238
GLint slot = c.textureSampler.slot;
1239
if (slot != activeSlot) {
1240
glActiveTexture(GL_TEXTURE0 + slot);
1241
activeSlot = slot;
1242
}
1243
GLRTexture *tex = curTex[slot];
1244
if (!tex) {
1245
break;
1246
}
1247
CHECK_GL_ERROR_IF_DEBUG();
1248
if (tex->canWrap) {
1249
if (tex->wrapS != c.textureSampler.wrapS) {
1250
glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, c.textureSampler.wrapS);
1251
tex->wrapS = c.textureSampler.wrapS;
1252
}
1253
if (tex->wrapT != c.textureSampler.wrapT) {
1254
glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, c.textureSampler.wrapT);
1255
tex->wrapT = c.textureSampler.wrapT;
1256
}
1257
}
1258
CHECK_GL_ERROR_IF_DEBUG();
1259
if (tex->magFilter != c.textureSampler.magFilter) {
1260
glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, c.textureSampler.magFilter);
1261
tex->magFilter = c.textureSampler.magFilter;
1262
}
1263
CHECK_GL_ERROR_IF_DEBUG();
1264
if (tex->minFilter != c.textureSampler.minFilter) {
1265
glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, c.textureSampler.minFilter);
1266
tex->minFilter = c.textureSampler.minFilter;
1267
}
1268
CHECK_GL_ERROR_IF_DEBUG();
1269
if (tex->anisotropy != c.textureSampler.anisotropy) {
1270
if (c.textureSampler.anisotropy != 0.0f) {
1271
glTexParameterf(tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, c.textureSampler.anisotropy);
1272
}
1273
tex->anisotropy = c.textureSampler.anisotropy;
1274
}
1275
CHECK_GL_ERROR_IF_DEBUG();
1276
break;
1277
}
1278
case GLRRenderCommand::TEXTURELOD:
1279
{
1280
GLint slot = c.textureLod.slot;
1281
if (slot != activeSlot) {
1282
glActiveTexture(GL_TEXTURE0 + slot);
1283
activeSlot = slot;
1284
}
1285
GLRTexture *tex = curTex[slot];
1286
if (!tex) {
1287
break;
1288
}
1289
#ifndef USING_GLES2
1290
if (tex->lodBias != c.textureLod.lodBias && !gl_extensions.IsGLES) {
1291
glTexParameterf(tex->target, GL_TEXTURE_LOD_BIAS, c.textureLod.lodBias);
1292
tex->lodBias = c.textureLod.lodBias;
1293
}
1294
#endif
1295
if (tex->minLod != c.textureLod.minLod) {
1296
glTexParameterf(tex->target, GL_TEXTURE_MIN_LOD, c.textureLod.minLod);
1297
tex->minLod = c.textureLod.minLod;
1298
}
1299
if (tex->maxLod != c.textureLod.maxLod) {
1300
glTexParameterf(tex->target, GL_TEXTURE_MAX_LOD, c.textureLod.maxLod);
1301
tex->maxLod = c.textureLod.maxLod;
1302
}
1303
break;
1304
}
1305
case GLRRenderCommand::TEXTURE_SUBIMAGE:
1306
{
1307
GLint slot = c.texture_subimage.slot;
1308
if (slot != activeSlot) {
1309
glActiveTexture(GL_TEXTURE0 + slot);
1310
activeSlot = slot;
1311
}
1312
// TODO: Need bind?
1313
GLRTexture *tex = c.texture_subimage.texture;
1314
if (!c.texture_subimage.data)
1315
Crash();
1316
_assert_(tex->target == GL_TEXTURE_2D);
1317
// For things to show in RenderDoc, need to split into glTexImage2D(..., nullptr) and glTexSubImage.
1318
GLuint internalFormat, format, type;
1319
int alignment;
1320
Thin3DFormatToGLFormatAndType(c.texture_subimage.format, internalFormat, format, type, alignment);
1321
glTexSubImage2D(tex->target, c.texture_subimage.level, c.texture_subimage.x, c.texture_subimage.y, c.texture_subimage.width, c.texture_subimage.height, format, type, c.texture_subimage.data);
1322
if (c.texture_subimage.allocType == GLRAllocType::ALIGNED) {
1323
FreeAlignedMemory(c.texture_subimage.data);
1324
} else if (c.texture_subimage.allocType == GLRAllocType::NEW) {
1325
delete[] c.texture_subimage.data;
1326
}
1327
CHECK_GL_ERROR_IF_DEBUG();
1328
break;
1329
}
1330
case GLRRenderCommand::RASTER:
1331
if (c.raster.cullEnable) {
1332
if (!cullEnabled) {
1333
glEnable(GL_CULL_FACE);
1334
cullEnabled = true;
1335
}
1336
if (frontFace != c.raster.frontFace) {
1337
glFrontFace(c.raster.frontFace);
1338
frontFace = c.raster.frontFace;
1339
}
1340
if (cullFace != c.raster.cullFace) {
1341
glCullFace(c.raster.cullFace);
1342
cullFace = c.raster.cullFace;
1343
}
1344
} else if (/* !c.raster.cullEnable && */ cullEnabled) {
1345
glDisable(GL_CULL_FACE);
1346
cullEnabled = false;
1347
}
1348
if (c.raster.ditherEnable) {
1349
if (!ditherEnabled) {
1350
glEnable(GL_DITHER);
1351
ditherEnabled = true;
1352
}
1353
} else if (/* !c.raster.ditherEnable && */ ditherEnabled) {
1354
glDisable(GL_DITHER);
1355
ditherEnabled = false;
1356
}
1357
#ifndef USING_GLES2
1358
if (c.raster.depthClampEnable) {
1359
if (!depthClampEnabled) {
1360
glEnable(GL_DEPTH_CLAMP);
1361
depthClampEnabled = true;
1362
}
1363
} else if (/* !c.raster.depthClampEnable && */ depthClampEnabled) {
1364
glDisable(GL_DEPTH_CLAMP);
1365
depthClampEnabled = false;
1366
}
1367
#endif
1368
CHECK_GL_ERROR_IF_DEBUG();
1369
break;
1370
default:
1371
_assert_msg_(false, "Bad GLRRenderCommand: %d", (int)c.cmd);
1372
break;
1373
}
1374
}
1375
1376
for (int i = 0; i < 7; i++) {
1377
if (attrMask & (1 << i)) {
1378
glDisableVertexAttribArray(i);
1379
}
1380
}
1381
1382
if (activeSlot != 0) {
1383
glActiveTexture(GL_TEXTURE0);
1384
activeSlot = 0; // doesn't matter, just nice.
1385
}
1386
CHECK_GL_ERROR_IF_DEBUG();
1387
1388
// Wipe out the current state.
1389
if (curArrayBuffer != 0)
1390
glBindBuffer(GL_ARRAY_BUFFER, 0);
1391
if (curElemArrayBuffer != 0)
1392
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1393
if (last && gl_extensions.ARB_vertex_array_object) {
1394
glBindVertexArray(0);
1395
}
1396
if (last)
1397
glDisable(GL_SCISSOR_TEST);
1398
if (depthEnabled)
1399
glDisable(GL_DEPTH_TEST);
1400
if (stencilEnabled)
1401
glDisable(GL_STENCIL_TEST);
1402
if (blendEnabled)
1403
glDisable(GL_BLEND);
1404
if (cullEnabled)
1405
glDisable(GL_CULL_FACE);
1406
#ifndef USING_GLES2
1407
if (depthClampEnabled)
1408
glDisable(GL_DEPTH_CLAMP);
1409
if (!gl_extensions.IsGLES && logicEnabled) {
1410
glDisable(GL_COLOR_LOGIC_OP);
1411
}
1412
#endif
1413
for (size_t i = 0; i < ARRAY_SIZE(clipDistanceEnabled); ++i) {
1414
if (clipDistanceEnabled[i])
1415
glDisable(GL_CLIP_DISTANCE0 + (GLenum)i);
1416
}
1417
if ((colorMask & 15) != 15)
1418
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1419
CHECK_GL_ERROR_IF_DEBUG();
1420
}
1421
1422
void GLQueueRunner::PerformCopy(const GLRStep &step) {
1423
CHECK_GL_ERROR_IF_DEBUG();
1424
GLuint srcTex = 0;
1425
GLuint dstTex = 0;
1426
GLuint target = GL_TEXTURE_2D;
1427
1428
const GLRect2D &srcRect = step.copy.srcRect;
1429
const GLOffset2D &dstPos = step.copy.dstPos;
1430
1431
GLRFramebuffer *src = step.copy.src;
1432
GLRFramebuffer *dst = step.copy.dst;
1433
1434
int srcLevel = 0;
1435
int dstLevel = 0;
1436
int srcZ = 0;
1437
int dstZ = 0;
1438
int depth = 1;
1439
1440
switch (step.copy.aspectMask) {
1441
case GL_COLOR_BUFFER_BIT:
1442
srcTex = src->color_texture.texture;
1443
dstTex = dst->color_texture.texture;
1444
break;
1445
case GL_DEPTH_BUFFER_BIT:
1446
// TODO: Support depth copies.
1447
_assert_msg_(false, "Depth copies not yet supported - soon");
1448
target = GL_RENDERBUFFER;
1449
/*
1450
srcTex = src->depth.texture;
1451
dstTex = src->depth.texture;
1452
*/
1453
break;
1454
}
1455
1456
_dbg_assert_(srcTex);
1457
_dbg_assert_(dstTex);
1458
1459
_assert_msg_(caps_.framebufferCopySupported, "Image copy extension expected");
1460
1461
#if defined(USING_GLES2)
1462
#if !PPSSPP_PLATFORM(IOS)
1463
glCopyImageSubDataOES(
1464
srcTex, target, srcLevel, srcRect.x, srcRect.y, srcZ,
1465
dstTex, target, dstLevel, dstPos.x, dstPos.y, dstZ,
1466
srcRect.w, srcRect.h, depth);
1467
#endif
1468
#else
1469
if (gl_extensions.ARB_copy_image) {
1470
glCopyImageSubData(
1471
srcTex, target, srcLevel, srcRect.x, srcRect.y, srcZ,
1472
dstTex, target, dstLevel, dstPos.x, dstPos.y, dstZ,
1473
srcRect.w, srcRect.h, depth);
1474
} else if (gl_extensions.NV_copy_image) {
1475
// Older, pre GL 4.x NVIDIA cards.
1476
glCopyImageSubDataNV(
1477
srcTex, target, srcLevel, srcRect.x, srcRect.y, srcZ,
1478
dstTex, target, dstLevel, dstPos.x, dstPos.y, dstZ,
1479
srcRect.w, srcRect.h, depth);
1480
}
1481
#endif
1482
CHECK_GL_ERROR_IF_DEBUG();
1483
}
1484
1485
void GLQueueRunner::PerformReadback(const GLRStep &pass) {
1486
using namespace Draw;
1487
CHECK_GL_ERROR_IF_DEBUG();
1488
1489
GLRFramebuffer *fb = pass.readback.src;
1490
1491
fbo_bind_fb_target(true, fb ? fb->handle : 0);
1492
1493
// Reads from the "bound for read" framebuffer. Note that if there's no fb, it's not valid to call this.
1494
if (fb && (gl_extensions.GLES3 || !gl_extensions.IsGLES))
1495
glReadBuffer(GL_COLOR_ATTACHMENT0);
1496
1497
CHECK_GL_ERROR_IF_DEBUG();
1498
1499
// Always read back in 8888 format for the color aspect.
1500
GLuint format = GL_RGBA;
1501
GLuint type = GL_UNSIGNED_BYTE;
1502
int srcAlignment = 4;
1503
1504
#ifndef USING_GLES2
1505
if (pass.readback.aspectMask & GL_DEPTH_BUFFER_BIT) {
1506
format = GL_DEPTH_COMPONENT;
1507
type = GL_FLOAT;
1508
srcAlignment = 4;
1509
} else if (pass.readback.aspectMask & GL_STENCIL_BUFFER_BIT) {
1510
format = GL_STENCIL_INDEX;
1511
type = GL_UNSIGNED_BYTE;
1512
srcAlignment = 1;
1513
}
1514
#endif
1515
1516
readbackAspectMask_ = pass.readback.aspectMask;
1517
1518
int pixelStride = pass.readback.srcRect.w;
1519
// Apply the correct alignment.
1520
glPixelStorei(GL_PACK_ALIGNMENT, srcAlignment);
1521
if (!gl_extensions.IsGLES || gl_extensions.GLES3) {
1522
// Some drivers seem to require we specify this. See #8254.
1523
glPixelStorei(GL_PACK_ROW_LENGTH, pixelStride);
1524
}
1525
1526
GLRect2D rect = pass.readback.srcRect;
1527
1528
int readbackSize = srcAlignment * rect.w * rect.h;
1529
if (readbackSize > readbackBufferSize_) {
1530
delete[] readbackBuffer_;
1531
readbackBuffer_ = new uint8_t[readbackSize];
1532
readbackBufferSize_ = readbackSize;
1533
}
1534
1535
glReadPixels(rect.x, rect.y, rect.w, rect.h, format, type, readbackBuffer_);
1536
#ifdef DEBUG_READ_PIXELS
1537
LogReadPixelsError(glGetError());
1538
#endif
1539
if (!gl_extensions.IsGLES || gl_extensions.GLES3) {
1540
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1541
}
1542
CHECK_GL_ERROR_IF_DEBUG();
1543
}
1544
1545
void GLQueueRunner::PerformReadbackImage(const GLRStep &pass) {
1546
#ifndef USING_GLES2
1547
GLRTexture *tex = pass.readback_image.texture;
1548
GLRect2D rect = pass.readback_image.srcRect;
1549
1550
if (gl_extensions.VersionGEThan(4, 5)) {
1551
int size = 4 * rect.w * rect.h;
1552
if (size > readbackBufferSize_) {
1553
delete[] readbackBuffer_;
1554
readbackBuffer_ = new uint8_t[size];
1555
readbackBufferSize_ = size;
1556
}
1557
1558
glPixelStorei(GL_PACK_ALIGNMENT, 4);
1559
glGetTextureSubImage(tex->texture, pass.readback_image.mipLevel, rect.x, rect.y, 0, rect.w, rect.h, 1, GL_RGBA, GL_UNSIGNED_BYTE, readbackBufferSize_, readbackBuffer_);
1560
} else {
1561
glBindTexture(GL_TEXTURE_2D, tex->texture);
1562
1563
CHECK_GL_ERROR_IF_DEBUG();
1564
1565
GLint w, h;
1566
// This is only used for debugging (currently), and GL doesn't support a subrectangle.
1567
glGetTexLevelParameteriv(GL_TEXTURE_2D, pass.readback_image.mipLevel, GL_TEXTURE_WIDTH, &w);
1568
glGetTexLevelParameteriv(GL_TEXTURE_2D, pass.readback_image.mipLevel, GL_TEXTURE_HEIGHT, &h);
1569
1570
int size = 4 * std::max((int)w, rect.x + rect.w) * std::max((int)h, rect.y + rect.h);
1571
if (size > readbackBufferSize_) {
1572
delete[] readbackBuffer_;
1573
readbackBuffer_ = new uint8_t[size];
1574
readbackBufferSize_ = size;
1575
}
1576
1577
glPixelStorei(GL_PACK_ALIGNMENT, 4);
1578
glPixelStorei(GL_PACK_ROW_LENGTH, rect.x + rect.w);
1579
glGetTexImage(GL_TEXTURE_2D, pass.readback_image.mipLevel, GL_RGBA, GL_UNSIGNED_BYTE, readbackBuffer_);
1580
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1581
1582
if (rect.x != 0 || rect.y != 0) {
1583
int dstStride = 4 * rect.w;
1584
int srcStride = 4 * (rect.x + rect.w);
1585
int xoff = 4 * rect.x;
1586
int yoff = rect.y * srcStride;
1587
for (int y = 0; y < rect.h; ++y) {
1588
memmove(readbackBuffer_ + h * dstStride, readbackBuffer_ + yoff + h * srcStride + xoff, dstStride);
1589
}
1590
}
1591
}
1592
#endif
1593
1594
CHECK_GL_ERROR_IF_DEBUG();
1595
}
1596
1597
void GLQueueRunner::PerformBindFramebufferAsRenderTarget(const GLRStep &pass) {
1598
if (pass.render.framebuffer) {
1599
curFBWidth_ = pass.render.framebuffer->width;
1600
curFBHeight_ = pass.render.framebuffer->height;
1601
} else {
1602
curFBWidth_ = targetWidth_;
1603
curFBHeight_ = targetHeight_;
1604
}
1605
1606
curFB_ = pass.render.framebuffer;
1607
if (curFB_) {
1608
// Without FBO_ARB / GLES3, this will collide with bind_for_read, but there's nothing
1609
// in ES 2.0 that actually separate them anyway of course, so doesn't matter.
1610
fbo_bind_fb_target(false, curFB_->handle);
1611
} else {
1612
fbo_unbind();
1613
if (IsVREnabled()) {
1614
BindVRFramebuffer();
1615
}
1616
// Backbuffer is now bound.
1617
}
1618
CHECK_GL_ERROR_IF_DEBUG();
1619
}
1620
1621
void GLQueueRunner::CopyFromReadbackBuffer(GLRFramebuffer *framebuffer, int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) {
1622
// TODO: Maybe move data format conversion here, and always read back 8888. Drivers
1623
// don't usually provide very optimized conversion implementations, though some do.
1624
// Just need to be careful about dithering, which may break Danganronpa.
1625
int bpp = (int)Draw::DataFormatSizeInBytes(destFormat);
1626
if (!readbackBuffer_ || bpp <= 0 || !pixels) {
1627
// Something went wrong during the read and no readback buffer was allocated, probably.
1628
return;
1629
}
1630
1631
// Always read back in 8888 format for the color aspect.
1632
GLuint internalFormat = GL_RGBA;
1633
#ifndef USING_GLES2
1634
if (readbackAspectMask_ & GL_DEPTH_BUFFER_BIT) {
1635
internalFormat = GL_DEPTH_COMPONENT;
1636
} else if (readbackAspectMask_ & GL_STENCIL_BUFFER_BIT) {
1637
internalFormat = GL_STENCIL_INDEX;
1638
}
1639
#endif
1640
1641
bool convert = internalFormat == GL_RGBA && destFormat != Draw::DataFormat::R8G8B8A8_UNORM;
1642
if (convert) {
1643
// srcStride is width because we read back "packed" (with no gaps) from GL.
1644
ConvertFromRGBA8888(pixels, readbackBuffer_, pixelStride, width, width, height, destFormat);
1645
} else {
1646
for (int y = 0; y < height; y++) {
1647
memcpy(pixels + y * pixelStride * bpp, readbackBuffer_ + y * width * bpp, width * bpp);
1648
}
1649
}
1650
}
1651
1652
// On PC, we always use GL_DEPTH24_STENCIL8.
1653
// On Android, we try to use what's available.
1654
1655
#ifndef USING_GLES2
1656
void GLQueueRunner::fbo_ext_create(const GLRInitStep &step) {
1657
GLRFramebuffer *fbo = step.create_framebuffer.framebuffer;
1658
1659
CHECK_GL_ERROR_IF_DEBUG();
1660
1661
// Color texture is same everywhere
1662
glGenFramebuffersEXT(1, &fbo->handle);
1663
glGenTextures(1, &fbo->color_texture.texture);
1664
1665
// Create the surfaces.
1666
glBindTexture(GL_TEXTURE_2D, fbo->color_texture.texture);
1667
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1668
1669
fbo->color_texture.target = GL_TEXTURE_2D;
1670
fbo->color_texture.wrapS = GL_CLAMP_TO_EDGE;
1671
fbo->color_texture.wrapT = GL_CLAMP_TO_EDGE;
1672
fbo->color_texture.magFilter = GL_LINEAR;
1673
fbo->color_texture.minFilter = GL_LINEAR;
1674
fbo->color_texture.maxLod = 0.0f;
1675
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, fbo->color_texture.wrapS);
1676
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, fbo->color_texture.wrapT);
1677
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, fbo->color_texture.magFilter);
1678
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, fbo->color_texture.minFilter);
1679
1680
fbo->stencil_buffer = 0;
1681
fbo->z_buffer = 0;
1682
// 24-bit Z, 8-bit stencil
1683
glGenRenderbuffersEXT(1, &fbo->z_stencil_buffer);
1684
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
1685
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, fbo->width, fbo->height);
1686
// glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8, width, height);
1687
1688
// Bind it all together
1689
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
1690
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo->color_texture.texture, 0);
1691
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
1692
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
1693
1694
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
1695
switch (status) {
1696
case GL_FRAMEBUFFER_COMPLETE_EXT:
1697
// INFO_LOG(Log::G3D, "Framebuffer verified complete.");
1698
break;
1699
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
1700
ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_UNSUPPORTED");
1701
break;
1702
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
1703
ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
1704
break;
1705
default:
1706
_assert_msg_(false, "Other framebuffer error: %d", status);
1707
break;
1708
}
1709
// Unbind state we don't need
1710
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
1711
glBindTexture(GL_TEXTURE_2D, 0);
1712
1713
CHECK_GL_ERROR_IF_DEBUG();
1714
1715
currentDrawHandle_ = fbo->handle;
1716
currentReadHandle_ = fbo->handle;
1717
}
1718
#endif
1719
1720
GLenum GLQueueRunner::fbo_get_fb_target(bool read, GLuint **cached) {
1721
bool supportsBlit = gl_extensions.ARB_framebuffer_object;
1722
if (gl_extensions.IsGLES) {
1723
supportsBlit = (gl_extensions.GLES3 || gl_extensions.NV_framebuffer_blit);
1724
}
1725
1726
// Note: GL_FRAMEBUFFER_EXT and GL_FRAMEBUFFER have the same value, same with _NV.
1727
if (supportsBlit) {
1728
if (read) {
1729
*cached = &currentReadHandle_;
1730
return GL_READ_FRAMEBUFFER;
1731
} else {
1732
*cached = &currentDrawHandle_;
1733
return GL_DRAW_FRAMEBUFFER;
1734
}
1735
} else {
1736
*cached = &currentDrawHandle_;
1737
return GL_FRAMEBUFFER;
1738
}
1739
}
1740
1741
void GLQueueRunner::fbo_bind_fb_target(bool read, GLuint name) {
1742
CHECK_GL_ERROR_IF_DEBUG();
1743
GLuint *cached;
1744
GLenum target = fbo_get_fb_target(read, &cached);
1745
if (*cached != name) {
1746
if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) {
1747
glBindFramebuffer(target, name);
1748
} else {
1749
#ifndef USING_GLES2
1750
glBindFramebufferEXT(target, name);
1751
#endif
1752
}
1753
*cached = name;
1754
}
1755
CHECK_GL_ERROR_IF_DEBUG();
1756
}
1757
1758
void GLQueueRunner::fbo_unbind() {
1759
CHECK_GL_ERROR_IF_DEBUG();
1760
#ifndef USING_GLES2
1761
if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) {
1762
glBindFramebuffer(GL_FRAMEBUFFER, g_defaultFBO);
1763
} else if (gl_extensions.EXT_framebuffer_object) {
1764
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_defaultFBO);
1765
}
1766
#else
1767
glBindFramebuffer(GL_FRAMEBUFFER, g_defaultFBO);
1768
#endif
1769
1770
#if PPSSPP_PLATFORM(IOS) && !defined(__LIBRETRO__)
1771
bindDefaultFBO();
1772
#endif
1773
1774
currentDrawHandle_ = 0;
1775
currentReadHandle_ = 0;
1776
CHECK_GL_ERROR_IF_DEBUG();
1777
}
1778
1779
GLRFramebuffer::~GLRFramebuffer() {
1780
if (handle == 0 && z_stencil_buffer == 0 && z_buffer == 0 && stencil_buffer == 0)
1781
return;
1782
1783
CHECK_GL_ERROR_IF_DEBUG();
1784
if (handle) {
1785
if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) {
1786
glBindFramebuffer(GL_FRAMEBUFFER, handle);
1787
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
1788
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
1789
glBindFramebuffer(GL_FRAMEBUFFER, g_defaultFBO);
1790
glDeleteFramebuffers(1, &handle);
1791
#ifndef USING_GLES2
1792
} else if (gl_extensions.EXT_framebuffer_object) {
1793
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, handle);
1794
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
1795
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER_EXT, 0);
1796
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_defaultFBO);
1797
glDeleteFramebuffersEXT(1, &handle);
1798
#endif
1799
}
1800
}
1801
1802
// These can only be set when supported.
1803
if (z_stencil_buffer)
1804
glDeleteRenderbuffers(1, &z_stencil_buffer);
1805
if (z_buffer)
1806
glDeleteRenderbuffers(1, &z_buffer);
1807
if (stencil_buffer)
1808
glDeleteRenderbuffers(1, &stencil_buffer);
1809
CHECK_GL_ERROR_IF_DEBUG();
1810
}
1811
1812
std::string GLQueueRunner::StepToString(const GLRStep &step) const {
1813
char buffer[256];
1814
switch (step.stepType) {
1815
case GLRStepType::RENDER:
1816
{
1817
int w = step.render.framebuffer ? step.render.framebuffer->width : targetWidth_;
1818
int h = step.render.framebuffer ? step.render.framebuffer->height : targetHeight_;
1819
snprintf(buffer, sizeof(buffer), "RENDER %s %s (commands: %d, %dx%d)\n", step.tag, step.render.framebuffer ? step.render.framebuffer->Tag() : "", (int)step.commands.size(), w, h);
1820
break;
1821
}
1822
case GLRStepType::COPY:
1823
snprintf(buffer, sizeof(buffer), "COPY '%s' %s -> %s (%dx%d, %s)\n", step.tag, step.copy.src->Tag(), step.copy.dst->Tag(), step.copy.srcRect.w, step.copy.srcRect.h, GLRAspectToString((GLRAspect)step.copy.aspectMask));
1824
break;
1825
case GLRStepType::BLIT:
1826
snprintf(buffer, sizeof(buffer), "BLIT '%s' %s -> %s (%dx%d->%dx%d, %s)\n", step.tag, step.copy.src->Tag(), step.copy.dst->Tag(), step.blit.srcRect.w, step.blit.srcRect.h, step.blit.dstRect.w, step.blit.dstRect.h, GLRAspectToString((GLRAspect)step.blit.aspectMask));
1827
break;
1828
case GLRStepType::READBACK:
1829
snprintf(buffer, sizeof(buffer), "READBACK '%s' %s (%dx%d, %s)\n", step.tag, step.readback.src ? step.readback.src->Tag() : "(backbuffer)", step.readback.srcRect.w, step.readback.srcRect.h, GLRAspectToString((GLRAspect)step.readback.aspectMask));
1830
break;
1831
case GLRStepType::READBACK_IMAGE:
1832
snprintf(buffer, sizeof(buffer), "READBACK_IMAGE '%s' (%dx%d)\n", step.tag, step.readback_image.srcRect.w, step.readback_image.srcRect.h);
1833
break;
1834
case GLRStepType::RENDER_SKIP:
1835
snprintf(buffer, sizeof(buffer), "(RENDER_SKIP) %s\n", step.tag);
1836
break;
1837
default:
1838
buffer[0] = 0;
1839
break;
1840
}
1841
return std::string(buffer);
1842
}
1843
1844
const char *GLRAspectToString(GLRAspect aspect) {
1845
switch (aspect) {
1846
case GLR_ASPECT_COLOR: return "COLOR";
1847
case GLR_ASPECT_DEPTH: return "DEPTH";
1848
case GLR_ASPECT_STENCIL: return "STENCIL";
1849
default: return "N/A";
1850
}
1851
}
1852
1853
const char *RenderCommandToString(GLRRenderCommand cmd) {
1854
switch (cmd) {
1855
case GLRRenderCommand::DEPTH: return "DEPTH";
1856
case GLRRenderCommand::STENCIL: return "STENCIL";
1857
case GLRRenderCommand::BLEND: return "BLEND";
1858
case GLRRenderCommand::BLENDCOLOR: return "BLENDCOLOR";
1859
case GLRRenderCommand::LOGICOP: return "LOGICOP";
1860
case GLRRenderCommand::UNIFORM4I: return "UNIFORM4I";
1861
case GLRRenderCommand::UNIFORM4UI: return "UNIFORM4UI";
1862
case GLRRenderCommand::UNIFORM4F: return "UNIFORM4F";
1863
case GLRRenderCommand::UNIFORMMATRIX: return "UNIFORMMATRIX";
1864
case GLRRenderCommand::UNIFORMSTEREOMATRIX: return "UNIFORMSTEREOMATRIX";
1865
case GLRRenderCommand::TEXTURESAMPLER: return "TEXTURESAMPLER";
1866
case GLRRenderCommand::TEXTURELOD: return "TEXTURELOD";
1867
case GLRRenderCommand::VIEWPORT: return "VIEWPORT";
1868
case GLRRenderCommand::SCISSOR: return "SCISSOR";
1869
case GLRRenderCommand::RASTER: return "RASTER";
1870
case GLRRenderCommand::CLEAR: return "CLEAR";
1871
case GLRRenderCommand::INVALIDATE: return "INVALIDATE";
1872
case GLRRenderCommand::BINDPROGRAM: return "BINDPROGRAM";
1873
case GLRRenderCommand::BINDTEXTURE: return "BINDTEXTURE";
1874
case GLRRenderCommand::BIND_FB_TEXTURE: return "BIND_FB_TEXTURE";
1875
case GLRRenderCommand::BIND_VERTEX_BUFFER: return "BIND_VERTEX_BUFFER";
1876
case GLRRenderCommand::GENMIPS: return "GENMIPS";
1877
case GLRRenderCommand::DRAW: return "DRAW";
1878
case GLRRenderCommand::TEXTURE_SUBIMAGE: return "TEXTURE_SUBIMAGE";
1879
default: return "N/A";
1880
}
1881
}
1882
1883