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