CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

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

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/OpenGL/GLRenderManager.h
Views: 1401
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 <mutex>
10
#include <queue>
11
#include <condition_variable>
12
13
#include "Common/GPU/MiscTypes.h"
14
#include "Common/Data/Convert/SmallDataConvert.h"
15
#include "Common/Log.h"
16
#include "Common/GPU/OpenGL/GLQueueRunner.h"
17
#include "Common/GPU/OpenGL/GLFrameData.h"
18
#include "Common/GPU/OpenGL/GLCommon.h"
19
#include "Common/GPU/OpenGL/GLMemory.h"
20
21
class GLRInputLayout;
22
class GLPushBuffer;
23
24
namespace Draw {
25
class DrawContext;
26
}
27
28
constexpr int MAX_GL_TEXTURE_SLOTS = 8;
29
30
class GLRTexture {
31
public:
32
GLRTexture(const Draw::DeviceCaps &caps, int width, int height, int depth, int numMips);
33
~GLRTexture();
34
35
GLuint texture = 0;
36
uint16_t w;
37
uint16_t h;
38
uint16_t d;
39
40
// We don't trust OpenGL defaults - setting wildly off values ensures that we'll end up overwriting these parameters.
41
GLenum target = 0xFFFF;
42
GLenum wrapS = 0xFFFF;
43
GLenum wrapT = 0xFFFF;
44
GLenum magFilter = 0xFFFF;
45
GLenum minFilter = 0xFFFF;
46
uint8_t numMips = 0;
47
bool canWrap = true;
48
float anisotropy = -100000.0f;
49
float minLod = -1000.0f;
50
float maxLod = 1000.0f;
51
float lodBias = 0.0f;
52
};
53
54
class GLRFramebuffer {
55
public:
56
GLRFramebuffer(const Draw::DeviceCaps &caps, int _width, int _height, bool z_stencil, const char *tag)
57
: color_texture(caps, _width, _height, 1, 1), z_stencil_texture(caps, _width, _height, 1, 1),
58
width(_width), height(_height), z_stencil_(z_stencil) {
59
}
60
~GLRFramebuffer();
61
62
const char *Tag() const { return tag_.c_str(); }
63
64
GLuint handle = 0;
65
GLRTexture color_texture;
66
// Either z_stencil_texture, z_stencil_buffer, or (z_buffer and stencil_buffer) are set.
67
GLuint z_stencil_buffer = 0;
68
GLRTexture z_stencil_texture;
69
GLuint z_buffer = 0;
70
GLuint stencil_buffer = 0;
71
72
int width;
73
int height;
74
GLuint colorDepth = 0;
75
bool z_stencil_;
76
77
private:
78
std::string tag_;
79
};
80
81
// We need to create some custom heap-allocated types so we can forward things that need to be created on the GL thread, before
82
// they've actually been created.
83
84
class GLRShader {
85
public:
86
~GLRShader() {
87
if (shader) {
88
glDeleteShader(shader);
89
}
90
}
91
92
GLuint shader = 0;
93
bool valid = false;
94
// Warning: Won't know until a future frame.
95
bool failed = false;
96
std::string desc;
97
std::string code;
98
std::string error;
99
};
100
101
struct GLRProgramFlags {
102
bool supportDualSource : 1;
103
bool useClipDistance0 : 1;
104
bool useClipDistance1 : 1;
105
bool useClipDistance2 : 1;
106
};
107
108
// Unless you manage lifetimes in some smart way,
109
// your loc data for uniforms and samplers need to be in a struct
110
// derived from this, and passed into CreateProgram.
111
class GLRProgramLocData {
112
public:
113
virtual ~GLRProgramLocData() {}
114
};
115
116
class GLRProgram {
117
public:
118
~GLRProgram() {
119
if (deleteCallback_) {
120
deleteCallback_(deleteParam_);
121
}
122
if (program) {
123
glDeleteProgram(program);
124
}
125
delete locData_;
126
}
127
struct Semantic {
128
int location;
129
const char *attrib;
130
};
131
132
struct UniformLocQuery {
133
GLint *dest;
134
const char *name;
135
bool required;
136
};
137
138
struct Initializer {
139
GLint *uniform;
140
int type;
141
int value;
142
};
143
144
GLuint program = 0;
145
std::vector<Semantic> semantics_;
146
std::vector<UniformLocQuery> queries_;
147
std::vector<Initializer> initialize_;
148
149
GLRProgramLocData *locData_;
150
bool use_clip_distance[8]{};
151
152
struct UniformInfo {
153
int loc_;
154
};
155
156
// Must ONLY be called from GLQueueRunner!
157
// Also it's pretty slow...
158
int GetUniformLoc(const char *name) {
159
auto iter = uniformCache_.find(std::string(name));
160
int loc = -1;
161
if (iter != uniformCache_.end()) {
162
loc = iter->second.loc_;
163
} else {
164
loc = glGetUniformLocation(program, name);
165
UniformInfo info;
166
info.loc_ = loc;
167
uniformCache_[name] = info;
168
}
169
return loc;
170
}
171
172
void SetDeleteCallback(void(*cb)(void *), void *p) {
173
deleteCallback_ = cb;
174
deleteParam_ = p;
175
}
176
177
private:
178
void(*deleteCallback_)(void *) = nullptr;
179
void *deleteParam_ = nullptr;
180
181
std::unordered_map<std::string, UniformInfo> uniformCache_;
182
};
183
184
class GLRInputLayout {
185
public:
186
struct Entry {
187
int location;
188
int count;
189
GLenum type;
190
GLboolean normalized;
191
intptr_t offset;
192
};
193
std::vector<Entry> entries;
194
int stride;
195
int semanticsMask_ = 0;
196
};
197
198
enum class GLRRunType {
199
SUBMIT,
200
PRESENT,
201
SYNC,
202
EXIT,
203
};
204
205
class GLRenderManager;
206
class GLPushBuffer;
207
208
// These are enqueued from the main thread, and the render thread pops them off
209
struct GLRRenderThreadTask {
210
GLRRenderThreadTask(GLRRunType _runType) : runType(_runType) {}
211
212
std::vector<GLRStep *> steps;
213
FastVec<GLRInitStep> initSteps;
214
215
int frame = -1;
216
GLRRunType runType;
217
218
// Avoid copying these by accident.
219
GLRRenderThreadTask(GLRRenderThreadTask &) = delete;
220
GLRRenderThreadTask& operator =(GLRRenderThreadTask &) = delete;
221
};
222
223
// Note: The GLRenderManager is created and destroyed on the render thread, and the latter
224
// happens after the emu thread has been destroyed. Therefore, it's safe to run wild deleting stuff
225
// directly in the destructor.
226
class GLRenderManager {
227
public:
228
GLRenderManager(HistoryBuffer<FrameTimeData, FRAME_TIME_HISTORY_LENGTH> &frameTimeHistory);
229
~GLRenderManager();
230
231
GLRenderManager(GLRenderManager &) = delete;
232
GLRenderManager &operator=(GLRenderManager &) = delete;
233
234
void SetInvalidationCallback(InvalidationCallback callback) {
235
invalidationCallback_ = callback;
236
}
237
238
void ThreadStart(Draw::DrawContext *draw);
239
void ThreadEnd();
240
bool ThreadFrame(); // Returns true if it did anything. False means the queue was empty.
241
242
void SetErrorCallback(ErrorCallbackFn callback, void *userdata) {
243
queueRunner_.SetErrorCallback(callback, userdata);
244
}
245
void SetDeviceCaps(const Draw::DeviceCaps &caps) {
246
queueRunner_.SetDeviceCaps(caps);
247
caps_ = caps;
248
}
249
250
std::string GetGpuProfileString() const;
251
252
// Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again.
253
void BeginFrame(bool enableProfiling);
254
// Can run on a different thread!
255
void Finish();
256
void Present();
257
258
// Creation commands. These were not needed in Vulkan since there we can do that on the main thread.
259
// We pass in width/height here even though it's not strictly needed until we support glTextureStorage
260
// and then we'll also need formats and stuff.
261
GLRTexture *CreateTexture(GLenum target, int width, int height, int depth, int numMips) {
262
_dbg_assert_(target != 0);
263
GLRInitStep &step = initSteps_.push_uninitialized();
264
step.stepType = GLRInitStepType::CREATE_TEXTURE;
265
step.create_texture.texture = new GLRTexture(caps_, width, height, depth, numMips);
266
step.create_texture.texture->target = target;
267
return step.create_texture.texture;
268
}
269
270
GLRBuffer *CreateBuffer(GLuint target, size_t size, GLuint usage) {
271
GLRInitStep &step = initSteps_.push_uninitialized();
272
step.stepType = GLRInitStepType::CREATE_BUFFER;
273
step.create_buffer.buffer = new GLRBuffer(target, size);
274
step.create_buffer.size = (int)size;
275
step.create_buffer.usage = usage;
276
return step.create_buffer.buffer;
277
}
278
279
GLRShader *CreateShader(GLuint stage, const std::string &code, const std::string &desc) {
280
GLRInitStep &step = initSteps_.push_uninitialized();
281
step.stepType = GLRInitStepType::CREATE_SHADER;
282
step.create_shader.shader = new GLRShader();
283
step.create_shader.shader->desc = 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
void StopThread();
829
830
bool SawOutOfMemory() {
831
return queueRunner_.SawOutOfMemory();
832
}
833
834
// Only supports a common subset.
835
std::string GetGLString(int name) const {
836
return queueRunner_.GetGLString(name);
837
}
838
839
// Used during Android-style ugly shutdown. No need to have a way to set it back because we'll be
840
// destroyed.
841
void SetSkipGLCalls() {
842
skipGLCalls_ = true;
843
}
844
845
private:
846
bool Run(GLRRenderThreadTask &task);
847
848
// Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot).
849
void FlushSync();
850
851
// When using legacy functionality for push buffers (glBufferData), we need to flush them
852
// before actually making the glDraw* calls. It's best if the render manager handles that.
853
void RegisterPushBuffer(int frame, GLPushBuffer *buffer) {
854
frameData_[frame].activePushBuffers.insert(buffer);
855
}
856
857
GLFrameData frameData_[MAX_INFLIGHT_FRAMES];
858
859
// Submission time state
860
bool insideFrame_ = false;
861
862
GLRStep *curRenderStep_ = nullptr;
863
std::vector<GLRStep *> steps_;
864
FastVec<GLRInitStep> initSteps_;
865
866
// Execution time state
867
// TODO: Rename this, as we don't actually use a compile thread on OpenGL.
868
bool runCompileThread_ = true;
869
870
// Thread is managed elsewhere, and should call ThreadFrame.
871
GLQueueRunner queueRunner_;
872
873
// For pushing data on the queue.
874
std::mutex pushMutex_;
875
std::condition_variable pushCondVar_;
876
877
std::queue<GLRRenderThreadTask *> renderThreadQueue_;
878
879
// For readbacks and other reasons we need to sync with the render thread.
880
std::mutex syncMutex_;
881
std::condition_variable syncCondVar_;
882
883
bool firstFrame_ = true;
884
bool vrRenderStarted_ = false;
885
bool syncDone_ = false;
886
887
GLDeleter deleter_;
888
bool skipGLCalls_ = false;
889
890
int curFrame_ = 0;
891
892
std::function<void()> swapFunction_;
893
std::function<void(int)> swapIntervalFunction_;
894
GLBufferStrategy bufferStrategy_ = GLBufferStrategy::SUBDATA;
895
896
int inflightFrames_ = MAX_INFLIGHT_FRAMES;
897
int newInflightFrames_ = -1;
898
899
int swapInterval_ = 0;
900
bool swapIntervalChanged_ = true;
901
902
int targetWidth_ = 0;
903
int targetHeight_ = 0;
904
905
#ifdef _DEBUG
906
GLRProgram *curProgram_ = nullptr;
907
#endif
908
Draw::DeviceCaps caps_{};
909
910
std::string profilePassesString_;
911
InvalidationCallback invalidationCallback_;
912
913
uint64_t frameIdGen_ = FRAME_TIME_HISTORY_LENGTH;
914
HistoryBuffer<FrameTimeData, FRAME_TIME_HISTORY_LENGTH> &frameTimeHistory_;
915
};
916
917