Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/OpenGL/GLRenderManager.h
5657 views
1
#pragma once
2
3
#include <thread>
4
#include <unordered_map>
5
#include <vector>
6
#include <functional>
7
#include <set>
8
#include <string>
9
#include <string_view>
10
#include <mutex>
11
#include <queue>
12
#include <condition_variable>
13
14
#include "Common/GPU/MiscTypes.h"
15
#include "Common/Data/Convert/SmallDataConvert.h"
16
#include "Common/Log.h"
17
#include "Common/GPU/OpenGL/GLQueueRunner.h"
18
#include "Common/GPU/OpenGL/GLFrameData.h"
19
#include "Common/GPU/OpenGL/GLCommon.h"
20
#include "Common/GPU/OpenGL/GLMemory.h"
21
22
class GLRInputLayout;
23
class GLPushBuffer;
24
25
namespace Draw {
26
class DrawContext;
27
}
28
29
constexpr int MAX_GL_TEXTURE_SLOTS = 8;
30
31
class GLRTexture {
32
public:
33
GLRTexture(const Draw::DeviceCaps &caps, int width, int height, int depth, int numMips);
34
~GLRTexture();
35
36
GLuint texture = 0;
37
uint16_t w;
38
uint16_t h;
39
uint16_t d;
40
41
// We don't trust OpenGL defaults - setting wildly off values ensures that we'll end up overwriting these parameters.
42
GLenum target = 0xFFFF;
43
GLenum wrapS = 0xFFFF;
44
GLenum wrapT = 0xFFFF;
45
GLenum magFilter = 0xFFFF;
46
GLenum minFilter = 0xFFFF;
47
uint8_t numMips = 0;
48
bool canWrap = true;
49
float anisotropy = -100000.0f;
50
float minLod = -1000.0f;
51
float maxLod = 1000.0f;
52
float lodBias = 0.0f;
53
};
54
55
class GLRFramebuffer {
56
public:
57
GLRFramebuffer(const Draw::DeviceCaps &caps, int _width, int _height, bool z_stencil, const char *tag)
58
: color_texture(caps, _width, _height, 1, 1), z_stencil_texture(caps, _width, _height, 1, 1),
59
width(_width), height(_height), z_stencil_(z_stencil) {
60
}
61
~GLRFramebuffer();
62
63
const char *Tag() const { return tag_.c_str(); }
64
65
GLuint handle = 0;
66
GLRTexture color_texture;
67
// Either z_stencil_texture, z_stencil_buffer, or (z_buffer and stencil_buffer) are set.
68
GLuint z_stencil_buffer = 0;
69
GLRTexture z_stencil_texture;
70
GLuint z_buffer = 0;
71
GLuint stencil_buffer = 0;
72
73
int width;
74
int height;
75
GLuint colorDepth = 0;
76
bool z_stencil_;
77
78
private:
79
std::string tag_;
80
};
81
82
// We need to create some custom heap-allocated types so we can forward things that need to be created on the GL thread, before
83
// they've actually been created.
84
85
class GLRShader {
86
public:
87
explicit GLRShader(std::string_view _desc) : desc(_desc) {}
88
~GLRShader() {
89
if (shader) {
90
glDeleteShader(shader);
91
}
92
}
93
94
GLuint shader = 0;
95
bool valid = false;
96
// Warning: Won't know until a future frame.
97
bool failed = false;
98
std::string desc;
99
std::string code;
100
std::string error;
101
};
102
103
struct GLRProgramFlags {
104
bool supportDualSource : 1;
105
bool useClipDistance0 : 1;
106
bool useClipDistance1 : 1;
107
bool useClipDistance2 : 1;
108
};
109
110
// Unless you manage lifetimes in some smart way,
111
// your loc data for uniforms and samplers need to be in a struct
112
// derived from this, and passed into CreateProgram.
113
class GLRProgramLocData {
114
public:
115
virtual ~GLRProgramLocData() {}
116
};
117
118
class GLRProgram {
119
public:
120
~GLRProgram() {
121
if (deleteCallback_) {
122
deleteCallback_(deleteParam_);
123
}
124
if (program) {
125
glDeleteProgram(program);
126
}
127
delete locData_;
128
}
129
struct Semantic {
130
int location;
131
const char *attrib;
132
};
133
134
struct UniformLocQuery {
135
GLint *dest;
136
const char *name;
137
bool required;
138
};
139
140
struct Initializer {
141
GLint *uniform;
142
int type;
143
int value;
144
};
145
146
GLuint program = 0;
147
std::vector<Semantic> semantics_;
148
std::vector<UniformLocQuery> queries_;
149
std::vector<Initializer> initialize_;
150
151
GLRProgramLocData *locData_;
152
bool use_clip_distance[8]{};
153
154
struct UniformInfo {
155
int loc_;
156
};
157
158
// Must ONLY be called from GLQueueRunner!
159
// Also it's pretty slow...
160
int GetUniformLoc(const char *name) {
161
auto iter = uniformCache_.find(std::string(name));
162
int loc = -1;
163
if (iter != uniformCache_.end()) {
164
loc = iter->second.loc_;
165
} else {
166
loc = glGetUniformLocation(program, name);
167
UniformInfo info;
168
info.loc_ = loc;
169
uniformCache_[name] = info;
170
}
171
return loc;
172
}
173
174
void SetDeleteCallback(void(*cb)(void *), void *p) {
175
deleteCallback_ = cb;
176
deleteParam_ = p;
177
}
178
179
private:
180
void(*deleteCallback_)(void *) = nullptr;
181
void *deleteParam_ = nullptr;
182
183
std::unordered_map<std::string, UniformInfo> uniformCache_;
184
};
185
186
class GLRInputLayout {
187
public:
188
struct Entry {
189
int location;
190
int count;
191
GLenum type;
192
GLboolean normalized;
193
intptr_t offset;
194
};
195
std::vector<Entry> entries;
196
int stride;
197
int semanticsMask_ = 0;
198
};
199
200
enum class GLRRunType {
201
SUBMIT,
202
PRESENT,
203
SYNC,
204
};
205
206
class GLRenderManager;
207
class GLPushBuffer;
208
209
// These are enqueued from the main thread, and the render thread pops them off
210
struct GLRRenderThreadTask {
211
GLRRenderThreadTask(GLRRunType _runType) : runType(_runType) {}
212
213
std::vector<GLRStep *> steps;
214
FastVec<GLRInitStep> initSteps;
215
216
int frame = -1;
217
GLRRunType runType;
218
219
// Avoid copying these by accident.
220
GLRRenderThreadTask(GLRRenderThreadTask &) = delete;
221
GLRRenderThreadTask& operator =(GLRRenderThreadTask &) = delete;
222
};
223
224
// Note: The GLRenderManager is created and destroyed on the render thread, and the latter
225
// happens after the emu thread has been destroyed. Therefore, it's safe to run wild deleting stuff
226
// directly in the destructor.
227
class GLRenderManager {
228
public:
229
GLRenderManager(HistoryBuffer<FrameTimeData, FRAME_TIME_HISTORY_LENGTH> &frameTimeHistory);
230
~GLRenderManager();
231
232
GLRenderManager(GLRenderManager &) = delete;
233
GLRenderManager &operator=(GLRenderManager &) = delete;
234
235
void SetInvalidationCallback(InvalidationCallback callback) {
236
invalidationCallback_ = callback;
237
}
238
239
void ThreadStart(Draw::DrawContext *draw);
240
void ThreadEnd();
241
bool ThreadFrame(bool waitIfEmpty); // Returns true if it did anything. False means the queue was empty.
242
243
void SetErrorCallback(ErrorCallbackFn callback, void *userdata) {
244
queueRunner_.SetErrorCallback(callback, userdata);
245
}
246
void SetDeviceCaps(const Draw::DeviceCaps &caps) {
247
queueRunner_.SetDeviceCaps(caps);
248
caps_ = caps;
249
}
250
251
std::string GetGpuProfileString() const;
252
253
// Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again.
254
void BeginFrame(bool enableProfiling);
255
// Can run on a different thread!
256
void Finish();
257
void Present();
258
259
// Creation commands. These were not needed in Vulkan since there we can do that on the main thread.
260
// We pass in width/height here even though it's not strictly needed until we support glTextureStorage
261
// and then we'll also need formats and stuff.
262
GLRTexture *CreateTexture(GLenum target, int width, int height, int depth, int numMips) {
263
_dbg_assert_(target != 0);
264
GLRInitStep &step = initSteps_.push_uninitialized();
265
step.stepType = GLRInitStepType::CREATE_TEXTURE;
266
step.create_texture.texture = new GLRTexture(caps_, width, height, depth, numMips);
267
step.create_texture.texture->target = target;
268
return step.create_texture.texture;
269
}
270
271
GLRBuffer *CreateBuffer(GLuint target, size_t size, GLuint usage) {
272
GLRInitStep &step = initSteps_.push_uninitialized();
273
step.stepType = GLRInitStepType::CREATE_BUFFER;
274
step.create_buffer.buffer = new GLRBuffer(target, size);
275
step.create_buffer.size = (int)size;
276
step.create_buffer.usage = usage;
277
return step.create_buffer.buffer;
278
}
279
280
GLRShader *CreateShader(GLuint stage, const std::string &code, std::string_view desc) {
281
GLRInitStep &step = initSteps_.push_uninitialized();
282
step.stepType = GLRInitStepType::CREATE_SHADER;
283
step.create_shader.shader = new GLRShader(desc);
284
step.create_shader.stage = stage;
285
step.create_shader.code = new char[code.size() + 1];
286
memcpy(step.create_shader.code, code.data(), code.size() + 1);
287
return step.create_shader.shader;
288
}
289
290
GLRFramebuffer *CreateFramebuffer(int width, int height, bool z_stencil, const char *tag) {
291
_dbg_assert_(width > 0 && height > 0 && tag != nullptr);
292
293
GLRInitStep &step = initSteps_.push_uninitialized();
294
step.stepType = GLRInitStepType::CREATE_FRAMEBUFFER;
295
step.create_framebuffer.framebuffer = new GLRFramebuffer(caps_, width, height, z_stencil, tag);
296
return step.create_framebuffer.framebuffer;
297
}
298
299
// Can't replace uniform initializers with direct calls to SetUniform() etc because there might
300
// not be an active render pass.
301
GLRProgram *CreateProgram(
302
std::vector<GLRShader *> shaders, std::vector<GLRProgram::Semantic> semantics, std::vector<GLRProgram::UniformLocQuery> queries,
303
std::vector<GLRProgram::Initializer> initializers, GLRProgramLocData *locData, const GLRProgramFlags &flags) {
304
GLRInitStep &step = initSteps_.push_uninitialized();
305
step.stepType = GLRInitStepType::CREATE_PROGRAM;
306
_assert_(shaders.size() <= ARRAY_SIZE(step.create_program.shaders));
307
step.create_program.program = new GLRProgram();
308
step.create_program.program->semantics_ = semantics;
309
step.create_program.program->queries_ = queries;
310
step.create_program.program->initialize_ = initializers;
311
step.create_program.program->locData_ = locData;
312
step.create_program.program->use_clip_distance[0] = flags.useClipDistance0;
313
step.create_program.program->use_clip_distance[1] = flags.useClipDistance1;
314
step.create_program.program->use_clip_distance[2] = flags.useClipDistance2;
315
step.create_program.support_dual_source = flags.supportDualSource;
316
_assert_msg_(shaders.size() > 0, "Can't create a program with zero shaders");
317
for (size_t i = 0; i < shaders.size(); i++) {
318
step.create_program.shaders[i] = shaders[i];
319
}
320
#ifdef _DEBUG
321
for (auto &iter : queries) {
322
_dbg_assert_(iter.name);
323
}
324
for (auto &sem : semantics) {
325
_dbg_assert_(sem.attrib);
326
}
327
#endif
328
step.create_program.num_shaders = (int)shaders.size();
329
return step.create_program.program;
330
}
331
332
GLRInputLayout *CreateInputLayout(const std::vector<GLRInputLayout::Entry> &entries, int stride) {
333
GLRInitStep &step = initSteps_.push_uninitialized();
334
step.stepType = GLRInitStepType::CREATE_INPUT_LAYOUT;
335
step.create_input_layout.inputLayout = new GLRInputLayout();
336
step.create_input_layout.inputLayout->entries = entries;
337
step.create_input_layout.inputLayout->stride = stride;
338
for (auto &iter : step.create_input_layout.inputLayout->entries) {
339
step.create_input_layout.inputLayout->semanticsMask_ |= 1 << iter.location;
340
}
341
return step.create_input_layout.inputLayout;
342
}
343
344
GLPushBuffer *CreatePushBuffer(int frame, GLuint target, size_t size, const char *tag) {
345
GLPushBuffer *push = new GLPushBuffer(this, target, size, tag);
346
RegisterPushBuffer(frame, push);
347
return push;
348
}
349
350
void DeleteShader(GLRShader *shader) {
351
_dbg_assert_(shader != nullptr);
352
deleter_.shaders.push_back(shader);
353
}
354
void DeleteProgram(GLRProgram *program) {
355
_dbg_assert_(program != nullptr);
356
deleter_.programs.push_back(program);
357
}
358
void DeleteBuffer(GLRBuffer *buffer) {
359
_dbg_assert_(buffer != nullptr);
360
deleter_.buffers.push_back(buffer);
361
}
362
void DeleteTexture(GLRTexture *texture) {
363
_dbg_assert_(texture != nullptr);
364
deleter_.textures.push_back(texture);
365
}
366
void DeleteInputLayout(GLRInputLayout *inputLayout) {
367
_dbg_assert_(inputLayout != nullptr);
368
deleter_.inputLayouts.push_back(inputLayout);
369
}
370
void DeleteFramebuffer(GLRFramebuffer *framebuffer) {
371
_dbg_assert_(framebuffer != nullptr);
372
deleter_.framebuffers.push_back(framebuffer);
373
}
374
void DeletePushBuffer(GLPushBuffer *pushbuffer) {
375
_dbg_assert_(pushbuffer != nullptr);
376
deleter_.pushBuffers.push_back(pushbuffer);
377
}
378
379
bool IsInRenderPass() const {
380
return curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER;
381
}
382
383
// This starts a new step (like a "render pass" in Vulkan).
384
//
385
// After a "CopyFramebuffer" or the other functions that start "steps", you need to call this before
386
// making any new render state changes or draw calls.
387
//
388
// The following state needs to be reset by the caller after calling this (and will thus not safely carry over from
389
// the previous one):
390
// * Viewport/Scissor
391
// * Depth/stencil
392
// * Blend
393
// * Raster state like primitive, culling, etc.
394
//
395
// It can be useful to use GetCurrentStepId() to figure out when you need to send all this state again, if you're
396
// not keeping track of your calls to this function on your own.
397
void BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag);
398
399
// Binds a framebuffer as a texture, for the following draws.
400
void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit);
401
402
bool CopyFramebufferToMemory(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, Draw::ReadbackMode mode, const char *tag);
403
void CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag);
404
405
void CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLOffset2D dstPos, int aspectMask, const char *tag);
406
void BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLRect2D dstRect, int aspectMask, bool filter, const char *tag);
407
408
// Takes ownership of data if deleteData = true.
409
void BufferSubdata(GLRBuffer *buffer, size_t offset, size_t size, uint8_t *data, bool deleteData = true) {
410
// TODO: Maybe should be a render command instead of an init command? When possible it's better as
411
// an init command, that's for sure.
412
GLRInitStep &step = initSteps_.push_uninitialized();
413
step.stepType = GLRInitStepType::BUFFER_SUBDATA;
414
_dbg_assert_(offset <= buffer->size_ - size);
415
step.buffer_subdata.buffer = buffer;
416
step.buffer_subdata.offset = (int)offset;
417
step.buffer_subdata.size = (int)size;
418
step.buffer_subdata.data = data;
419
step.buffer_subdata.deleteData = deleteData;
420
}
421
422
// Takes ownership over the data pointer and delete[]-s it.
423
void TextureImage(GLRTexture *texture, int level, int width, int height, int depth, Draw::DataFormat format, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW, bool linearFilter = false) {
424
GLRInitStep &step = initSteps_.push_uninitialized();
425
step.stepType = GLRInitStepType::TEXTURE_IMAGE;
426
step.texture_image.texture = texture;
427
step.texture_image.data = data;
428
step.texture_image.format = format;
429
step.texture_image.level = level;
430
step.texture_image.width = width;
431
step.texture_image.height = height;
432
step.texture_image.depth = depth;
433
step.texture_image.allocType = allocType;
434
step.texture_image.linearFilter = linearFilter;
435
}
436
437
void TextureSubImage(int slot, GLRTexture *texture, int level, int x, int y, int width, int height, Draw::DataFormat format, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW) {
438
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
439
GLRRenderData _data(GLRRenderCommand::TEXTURE_SUBIMAGE);
440
_data.texture_subimage.texture = texture;
441
_data.texture_subimage.data = data;
442
_data.texture_subimage.format = format;
443
_data.texture_subimage.level = level;
444
_data.texture_subimage.x = x;
445
_data.texture_subimage.y = y;
446
_data.texture_subimage.width = width;
447
_data.texture_subimage.height = height;
448
_data.texture_subimage.allocType = allocType;
449
_data.texture_subimage.slot = slot;
450
curRenderStep_->commands.push_back(_data);
451
}
452
453
void FinalizeTexture(GLRTexture *texture, int loadedLevels, bool genMips) {
454
GLRInitStep &step = initSteps_.push_uninitialized();
455
step.stepType = GLRInitStepType::TEXTURE_FINALIZE;
456
step.texture_finalize.texture = texture;
457
step.texture_finalize.loadedLevels = loadedLevels;
458
step.texture_finalize.genMips = genMips;
459
}
460
461
void BindTexture(int slot, GLRTexture *tex) {
462
if (!curRenderStep_ && !tex) {
463
// Likely a pre-emptive bindtexture for D3D11 to avoid hazards. Not necessary.
464
// This can happen in BlitUsingRaster.
465
return;
466
}
467
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
468
_dbg_assert_(slot < MAX_GL_TEXTURE_SLOTS);
469
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
470
data.cmd = GLRRenderCommand::BINDTEXTURE;
471
data.texture.slot = slot;
472
data.texture.texture = tex;
473
}
474
475
void BindProgram(GLRProgram *program) {
476
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
477
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
478
data.cmd = GLRRenderCommand::BINDPROGRAM;
479
_dbg_assert_(program != nullptr);
480
data.program.program = program;
481
#ifdef _DEBUG
482
curProgram_ = program;
483
#endif
484
}
485
486
void SetDepth(bool enabled, bool write, GLenum func) {
487
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
488
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
489
data.cmd = GLRRenderCommand::DEPTH;
490
data.depth.enabled = enabled;
491
data.depth.write = write;
492
data.depth.func = func;
493
}
494
495
void SetViewport(const GLRViewport &vp) {
496
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
497
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
498
data.cmd = GLRRenderCommand::VIEWPORT;
499
data.viewport.vp = vp;
500
}
501
502
void SetScissor(const GLRect2D &rc) {
503
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
504
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
505
data.cmd = GLRRenderCommand::SCISSOR;
506
data.scissor.rc = rc;
507
}
508
509
void SetUniformI(const GLint *loc, int count, const int *udata) {
510
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
511
#ifdef _DEBUG
512
_dbg_assert_(curProgram_);
513
#endif
514
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
515
data.cmd = GLRRenderCommand::UNIFORM4I;
516
data.uniform4.name = nullptr;
517
data.uniform4.loc = loc;
518
data.uniform4.count = count;
519
memcpy(data.uniform4.v, udata, sizeof(int) * count);
520
}
521
522
void SetUniformI1(const GLint *loc, int udata) {
523
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
524
#ifdef _DEBUG
525
_dbg_assert_(curProgram_);
526
#endif
527
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
528
data.cmd = GLRRenderCommand::UNIFORM4I;
529
data.uniform4.name = nullptr;
530
data.uniform4.loc = loc;
531
data.uniform4.count = 1;
532
memcpy(data.uniform4.v, &udata, sizeof(udata));
533
}
534
535
void SetUniformUI(const GLint *loc, int count, const uint32_t *udata) {
536
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
537
#ifdef _DEBUG
538
_dbg_assert_(curProgram_);
539
#endif
540
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
541
data.cmd = GLRRenderCommand::UNIFORM4UI;
542
data.uniform4.name = nullptr;
543
data.uniform4.loc = loc;
544
data.uniform4.count = count;
545
memcpy(data.uniform4.v, udata, sizeof(uint32_t) * count);
546
}
547
548
void SetUniformUI1(const GLint *loc, uint32_t udata) {
549
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
550
#ifdef _DEBUG
551
_dbg_assert_(curProgram_);
552
#endif
553
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
554
data.cmd = GLRRenderCommand::UNIFORM4UI;
555
data.uniform4.name = nullptr;
556
data.uniform4.loc = loc;
557
data.uniform4.count = 1;
558
memcpy(data.uniform4.v, &udata, sizeof(udata));
559
}
560
561
void SetUniformF(const GLint *loc, int count, const float *udata) {
562
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
563
#ifdef _DEBUG
564
_dbg_assert_(curProgram_);
565
#endif
566
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
567
data.cmd = GLRRenderCommand::UNIFORM4F;
568
data.uniform4.name = nullptr;
569
data.uniform4.loc = loc;
570
data.uniform4.count = count;
571
memcpy(data.uniform4.v, udata, sizeof(float) * count);
572
}
573
574
void SetUniformF1(const GLint *loc, const float udata) {
575
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
576
#ifdef _DEBUG
577
_dbg_assert_(curProgram_);
578
#endif
579
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
580
data.cmd = GLRRenderCommand::UNIFORM4F;
581
data.uniform4.name = nullptr;
582
data.uniform4.loc = loc;
583
data.uniform4.count = 1;
584
memcpy(data.uniform4.v, &udata, sizeof(float));
585
}
586
587
void SetUniformF(const char *name, int count, const float *udata) {
588
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
589
#ifdef _DEBUG
590
_dbg_assert_(curProgram_);
591
#endif
592
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
593
data.cmd = GLRRenderCommand::UNIFORM4F;
594
data.uniform4.name = name;
595
data.uniform4.loc = nullptr;
596
data.uniform4.count = count;
597
memcpy(data.uniform4.v, udata, sizeof(float) * count);
598
}
599
600
void SetUniformM4x4(const GLint *loc, const float *udata) {
601
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
602
#ifdef _DEBUG
603
_dbg_assert_(curProgram_);
604
#endif
605
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
606
data.cmd = GLRRenderCommand::UNIFORMMATRIX;
607
data.uniformMatrix4.name = nullptr;
608
data.uniformMatrix4.loc = loc;
609
memcpy(data.uniformMatrix4.m, udata, sizeof(float) * 16);
610
}
611
612
void SetUniformM4x4Stereo(const char *name, const GLint *loc, const float *left, const float *right) {
613
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
614
#ifdef _DEBUG
615
_dbg_assert_(curProgram_);
616
#endif
617
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
618
data.cmd = GLRRenderCommand::UNIFORMSTEREOMATRIX;
619
data.uniformStereoMatrix4.name = name;
620
data.uniformStereoMatrix4.loc = loc;
621
data.uniformStereoMatrix4.mData = new float[32];
622
memcpy(&data.uniformStereoMatrix4.mData[0], left, sizeof(float) * 16);
623
memcpy(&data.uniformStereoMatrix4.mData[16], right, sizeof(float) * 16);
624
}
625
626
void SetUniformM4x4(const char *name, const float *udata) {
627
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
628
#ifdef _DEBUG
629
_dbg_assert_(curProgram_);
630
#endif
631
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
632
data.cmd = GLRRenderCommand::UNIFORMMATRIX;
633
data.uniformMatrix4.name = name;
634
data.uniformMatrix4.loc = nullptr;
635
memcpy(data.uniformMatrix4.m, udata, sizeof(float) * 16);
636
}
637
638
void SetBlendAndMask(int colorMask, bool blendEnabled, GLenum srcColor, GLenum dstColor, GLenum srcAlpha, GLenum dstAlpha, GLenum funcColor, GLenum funcAlpha) {
639
// Make this one only a non-debug _assert_, since it often comes first.
640
// Lets us collect info about this potential crash through assert extra data.
641
_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
642
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
643
data.cmd = GLRRenderCommand::BLEND;
644
data.blend.mask = colorMask;
645
data.blend.enabled = blendEnabled;
646
data.blend.srcColor = srcColor;
647
data.blend.dstColor = dstColor;
648
data.blend.srcAlpha = srcAlpha;
649
data.blend.dstAlpha = dstAlpha;
650
data.blend.funcColor = funcColor;
651
data.blend.funcAlpha = funcAlpha;
652
}
653
654
void SetNoBlendAndMask(int colorMask) {
655
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
656
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
657
data.cmd = GLRRenderCommand::BLEND;
658
data.blend.mask = colorMask;
659
data.blend.enabled = false;
660
}
661
662
#ifndef USING_GLES2
663
void SetLogicOp(bool enabled, GLenum logicOp) {
664
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
665
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
666
data.cmd = GLRRenderCommand::LOGICOP;
667
data.logic.enabled = enabled;
668
data.logic.logicOp = logicOp;
669
}
670
#endif
671
672
void SetStencil(bool enabled, GLenum func, uint8_t refValue, uint8_t compareMask, uint8_t writeMask, GLenum sFail, GLenum zFail, GLenum pass) {
673
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
674
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
675
data.cmd = GLRRenderCommand::STENCIL;
676
data.stencil.enabled = enabled;
677
data.stencil.func = func;
678
data.stencil.ref = refValue;
679
data.stencil.compareMask = compareMask;
680
data.stencil.writeMask = writeMask;
681
data.stencil.sFail = sFail;
682
data.stencil.zFail = zFail;
683
data.stencil.pass = pass;
684
}
685
686
void SetStencilDisabled() {
687
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
688
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
689
data.cmd = GLRRenderCommand::STENCIL;
690
data.stencil.enabled = false;
691
}
692
693
void SetBlendFactor(const float color[4]) {
694
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
695
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
696
data.cmd = GLRRenderCommand::BLENDCOLOR;
697
CopyFloat4(data.blendColor.color, color);
698
}
699
700
void SetRaster(GLboolean cullEnable, GLenum frontFace, GLenum cullFace, GLboolean ditherEnable, GLboolean depthClamp) {
701
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
702
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
703
data.cmd = GLRRenderCommand::RASTER;
704
data.raster.cullEnable = cullEnable;
705
data.raster.frontFace = frontFace;
706
data.raster.cullFace = cullFace;
707
data.raster.ditherEnable = ditherEnable;
708
data.raster.depthClampEnable = depthClamp;
709
}
710
711
// Modifies the current texture as per GL specs, not global state.
712
void SetTextureSampler(int slot, GLenum wrapS, GLenum wrapT, GLenum magFilter, GLenum minFilter, float anisotropy) {
713
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
714
_dbg_assert_(slot < MAX_GL_TEXTURE_SLOTS);
715
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
716
data.cmd = GLRRenderCommand::TEXTURESAMPLER;
717
data.textureSampler.slot = slot;
718
data.textureSampler.wrapS = wrapS;
719
data.textureSampler.wrapT = wrapT;
720
data.textureSampler.magFilter = magFilter;
721
data.textureSampler.minFilter = minFilter;
722
data.textureSampler.anisotropy = anisotropy;
723
}
724
725
void SetTextureLod(int slot, float minLod, float maxLod, float lodBias) {
726
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
727
_dbg_assert_(slot < MAX_GL_TEXTURE_SLOTS);
728
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
729
data.cmd = GLRRenderCommand::TEXTURELOD;
730
data.textureLod.slot = slot;
731
data.textureLod.minLod = minLod;
732
data.textureLod.maxLod = maxLod;
733
data.textureLod.lodBias = lodBias;
734
}
735
736
// If scissorW == 0, no scissor is applied (the whole render target is cleared).
737
void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask, int colorMask, int scissorX, int scissorY, int scissorW, int scissorH) {
738
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
739
if (!clearMask)
740
return;
741
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
742
data.cmd = GLRRenderCommand::CLEAR;
743
data.clear.clearMask = clearMask;
744
data.clear.clearColor = clearColor;
745
data.clear.clearZ = clearZ;
746
data.clear.clearStencil = clearStencil;
747
data.clear.colorMask = colorMask;
748
data.clear.scissorX = scissorX;
749
data.clear.scissorY = scissorY;
750
data.clear.scissorW = scissorW;
751
data.clear.scissorH = scissorH;
752
}
753
754
void Draw(GLRInputLayout *inputLayout, GLRBuffer *vertexBuffer, uint32_t vertexOffset, GLenum mode, int first, int count) {
755
_dbg_assert_(vertexBuffer && curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
756
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
757
data.cmd = GLRRenderCommand::DRAW;
758
data.draw.inputLayout = inputLayout;
759
data.draw.vertexOffset = vertexOffset;
760
data.draw.vertexBuffer = vertexBuffer;
761
data.draw.indexBuffer = nullptr;
762
data.draw.mode = mode;
763
data.draw.first = first;
764
data.draw.count = count;
765
data.draw.indexType = 0;
766
}
767
768
// Would really love to have a basevertex parameter, but impossible in unextended GLES, without glDrawElementsBaseVertex, unfortunately.
769
void DrawIndexed(GLRInputLayout *inputLayout, GLRBuffer *vertexBuffer, uint32_t vertexOffset, GLRBuffer *indexBuffer, uint32_t indexOffset, GLenum mode, int count, GLenum indexType, int instances = 1) {
770
_dbg_assert_(vertexBuffer && indexBuffer && curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
771
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
772
data.cmd = GLRRenderCommand::DRAW;
773
data.draw.inputLayout = inputLayout;
774
data.draw.vertexOffset = vertexOffset;
775
data.draw.vertexBuffer = vertexBuffer;
776
data.draw.indexBuffer = indexBuffer;
777
data.draw.indexOffset = indexOffset;
778
data.draw.mode = mode;
779
data.draw.count = count;
780
data.draw.indexType = indexType;
781
data.draw.instances = instances;
782
}
783
784
enum { MAX_INFLIGHT_FRAMES = 3 };
785
786
void SetInflightFrames(int f) {
787
newInflightFrames_ = f < 1 || f > MAX_INFLIGHT_FRAMES ? MAX_INFLIGHT_FRAMES : f;
788
}
789
790
int GetCurFrame() const {
791
return curFrame_;
792
}
793
794
void Resize(int width, int height) {
795
targetWidth_ = width;
796
targetHeight_ = height;
797
queueRunner_.Resize(width, height);
798
}
799
800
void UnregisterPushBuffer(GLPushBuffer *buffer) {
801
int foundCount = 0;
802
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
803
auto iter = frameData_[i].activePushBuffers.find(buffer);
804
if (iter != frameData_[i].activePushBuffers.end()) {
805
frameData_[i].activePushBuffers.erase(iter);
806
foundCount++;
807
}
808
}
809
_dbg_assert_(foundCount == 1);
810
}
811
812
void SetSwapFunction(std::function<void()> swapFunction) {
813
swapFunction_ = swapFunction;
814
}
815
816
void SetSwapIntervalFunction(std::function<void(int)> swapIntervalFunction) {
817
swapIntervalFunction_ = swapIntervalFunction;
818
}
819
820
void SwapInterval(int interval) {
821
if (interval != swapInterval_) {
822
swapInterval_ = interval;
823
swapIntervalChanged_ = true;
824
}
825
}
826
827
void StartThread(); // Currently only used on iOS, since we fully recreate the context on Android
828
829
bool SawOutOfMemory() {
830
return queueRunner_.SawOutOfMemory();
831
}
832
833
// Only supports a common subset.
834
std::string GetGLString(int name) const {
835
return queueRunner_.GetGLString(name);
836
}
837
838
// Used during Android-style ugly shutdown. No need to have a way to set it back because we'll be
839
// destroyed.
840
void SetSkipGLCalls() {
841
skipGLCalls_ = true;
842
}
843
844
int GetNumSteps() const {
845
return (int)steps_.size();
846
}
847
848
private:
849
bool Run(GLRRenderThreadTask &task);
850
851
// Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot).
852
void FlushSync();
853
854
// When using legacy functionality for push buffers (glBufferData), we need to flush them
855
// before actually making the glDraw* calls. It's best if the render manager handles that.
856
void RegisterPushBuffer(int frame, GLPushBuffer *buffer) {
857
frameData_[frame].activePushBuffers.insert(buffer);
858
}
859
860
GLFrameData frameData_[MAX_INFLIGHT_FRAMES];
861
862
// Submission time state
863
bool insideFrame_ = false;
864
865
GLRStep *curRenderStep_ = nullptr;
866
std::vector<GLRStep *> steps_;
867
FastVec<GLRInitStep> initSteps_;
868
869
// Execution time state
870
// TODO: Rename this, as we don't actually use a compile thread on OpenGL.
871
bool runCompileThread_ = true;
872
873
// Thread is managed elsewhere, and should call ThreadFrame.
874
GLQueueRunner queueRunner_;
875
876
// For pushing data on the queue.
877
std::mutex pushMutex_;
878
std::condition_variable pushCondVar_;
879
880
std::queue<GLRRenderThreadTask *> renderThreadQueue_;
881
882
// For readbacks and other reasons we need to sync with the render thread.
883
std::mutex syncMutex_;
884
std::condition_variable syncCondVar_;
885
886
bool syncDone_ = false;
887
888
GLDeleter deleter_;
889
bool skipGLCalls_ = false;
890
891
int curFrame_ = 0;
892
893
std::function<void()> swapFunction_;
894
std::function<void(int)> swapIntervalFunction_;
895
GLBufferStrategy bufferStrategy_ = GLBufferStrategy::SUBDATA;
896
897
int inflightFrames_ = MAX_INFLIGHT_FRAMES;
898
int newInflightFrames_ = -1;
899
900
int swapInterval_ = 0;
901
bool swapIntervalChanged_ = true;
902
903
int targetWidth_ = 0;
904
int targetHeight_ = 0;
905
906
#ifdef _DEBUG
907
GLRProgram *curProgram_ = nullptr;
908
#endif
909
Draw::DeviceCaps caps_{};
910
911
std::string profilePassesString_;
912
InvalidationCallback invalidationCallback_;
913
914
uint64_t frameIdGen_ = FRAME_TIME_HISTORY_LENGTH;
915
HistoryBuffer<FrameTimeData, FRAME_TIME_HISTORY_LENGTH> &frameTimeHistory_;
916
};
917
918