Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/OpenGL/thin3d_gl.cpp
3189 views
1
#include <cstdio>
2
#include <vector>
3
#include <string>
4
#include <map>
5
6
#include "ppsspp_config.h"
7
8
#include "Common/Data/Convert/ColorConv.h"
9
#include "Common/Data/Convert/SmallDataConvert.h"
10
#include "Common/Math/math_util.h"
11
#include "Common/Math/lin/matrix4x4.h"
12
#include "Common/System/System.h"
13
#include "Common/Log.h"
14
#include "Common/GPU/thin3d.h"
15
#include "Common/GPU/Shader.h"
16
#include "Common/GPU/OpenGL/DataFormatGL.h"
17
#include "Common/GPU/OpenGL/GLCommon.h"
18
#include "Common/GPU/OpenGL/GLDebugLog.h"
19
#include "Common/GPU/OpenGL/GLFeatures.h"
20
21
#include "Common/GPU/OpenGL/GLRenderManager.h"
22
23
// #define DEBUG_READ_PIXELS 1
24
25
namespace Draw {
26
27
static const unsigned short compToGL[] = {
28
GL_NEVER,
29
GL_LESS,
30
GL_EQUAL,
31
GL_LEQUAL,
32
GL_GREATER,
33
GL_NOTEQUAL,
34
GL_GEQUAL,
35
GL_ALWAYS
36
};
37
38
static const unsigned short blendEqToGL[] = {
39
GL_FUNC_ADD,
40
GL_FUNC_SUBTRACT,
41
GL_FUNC_REVERSE_SUBTRACT,
42
GL_MIN,
43
GL_MAX,
44
};
45
46
static const unsigned short blendFactorToGL[] = {
47
GL_ZERO,
48
GL_ONE,
49
GL_SRC_COLOR,
50
GL_ONE_MINUS_SRC_COLOR,
51
GL_DST_COLOR,
52
GL_ONE_MINUS_DST_COLOR,
53
GL_SRC_ALPHA,
54
GL_ONE_MINUS_SRC_ALPHA,
55
GL_DST_ALPHA,
56
GL_ONE_MINUS_DST_ALPHA,
57
GL_CONSTANT_COLOR,
58
GL_ONE_MINUS_CONSTANT_COLOR,
59
GL_CONSTANT_ALPHA,
60
GL_ONE_MINUS_CONSTANT_ALPHA,
61
#if !defined(USING_GLES2) // TODO: Remove when we have better headers
62
GL_SRC1_COLOR,
63
GL_ONE_MINUS_SRC1_COLOR,
64
GL_SRC1_ALPHA,
65
GL_ONE_MINUS_SRC1_ALPHA,
66
#elif !PPSSPP_PLATFORM(IOS)
67
GL_SRC1_COLOR_EXT,
68
GL_ONE_MINUS_SRC1_COLOR_EXT,
69
GL_SRC1_ALPHA_EXT,
70
GL_ONE_MINUS_SRC1_ALPHA_EXT,
71
#else
72
GL_INVALID_ENUM,
73
GL_INVALID_ENUM,
74
GL_INVALID_ENUM,
75
GL_INVALID_ENUM,
76
#endif
77
};
78
79
static const unsigned short texWrapToGL[] = {
80
GL_REPEAT,
81
GL_MIRRORED_REPEAT,
82
GL_CLAMP_TO_EDGE,
83
#if !defined(USING_GLES2)
84
GL_CLAMP_TO_BORDER,
85
#else
86
GL_CLAMP_TO_EDGE,
87
#endif
88
};
89
90
static const unsigned short texFilterToGL[] = {
91
GL_NEAREST,
92
GL_LINEAR,
93
};
94
95
static const unsigned short texMipFilterToGL[2][2] = {
96
// Min nearest:
97
{ GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR },
98
// Min linear:
99
{ GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR },
100
};
101
102
#ifndef USING_GLES2
103
static const unsigned short logicOpToGL[] = {
104
GL_CLEAR,
105
GL_SET,
106
GL_COPY,
107
GL_COPY_INVERTED,
108
GL_NOOP,
109
GL_INVERT,
110
GL_AND,
111
GL_NAND,
112
GL_OR,
113
GL_NOR,
114
GL_XOR,
115
GL_EQUIV,
116
GL_AND_REVERSE,
117
GL_AND_INVERTED,
118
GL_OR_REVERSE,
119
GL_OR_INVERTED,
120
};
121
#endif
122
123
static const GLuint stencilOpToGL[8] = {
124
GL_KEEP,
125
GL_ZERO,
126
GL_REPLACE,
127
GL_INCR,
128
GL_DECR,
129
GL_INVERT,
130
GL_INCR_WRAP,
131
GL_DECR_WRAP,
132
};
133
134
static const unsigned short primToGL[] = {
135
GL_POINTS,
136
GL_LINES,
137
GL_LINE_STRIP,
138
GL_TRIANGLES,
139
GL_TRIANGLE_STRIP,
140
GL_TRIANGLE_FAN,
141
};
142
143
class OpenGLBuffer;
144
145
class OpenGLBlendState : public BlendState {
146
public:
147
bool enabled;
148
GLuint eqCol, eqAlpha;
149
GLuint srcCol, srcAlpha, dstCol, dstAlpha;
150
int colorMask;
151
// uint32_t fixedColor;
152
153
void Apply(GLRenderManager *render) {
154
render->SetBlendAndMask(colorMask, enabled, srcCol, dstCol, srcAlpha, dstAlpha, eqCol, eqAlpha);
155
}
156
};
157
158
class OpenGLSamplerState : public SamplerState {
159
public:
160
GLint wrapU;
161
GLint wrapV;
162
GLint wrapW;
163
GLint magFilt;
164
GLint minFilt;
165
GLint mipMinFilt;
166
};
167
168
class OpenGLDepthStencilState : public DepthStencilState {
169
public:
170
bool depthTestEnabled;
171
bool depthWriteEnabled;
172
GLuint depthComp;
173
// TODO: Two-sided. Although in practice, do we care?
174
bool stencilEnabled;
175
GLuint stencilFail;
176
GLuint stencilZFail;
177
GLuint stencilPass;
178
GLuint stencilCompareOp;
179
180
void Apply(GLRenderManager *render, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {
181
render->SetDepth(depthTestEnabled, depthWriteEnabled, depthComp);
182
render->SetStencil(
183
stencilEnabled, stencilCompareOp, stencilRef, stencilCompareMask,
184
stencilWriteMask, stencilFail, stencilZFail, stencilPass);
185
}
186
};
187
188
class OpenGLRasterState : public RasterState {
189
public:
190
void Apply(GLRenderManager *render) {
191
render->SetRaster(cullEnable, frontFace, cullMode, GL_FALSE, GL_FALSE);
192
}
193
194
GLboolean cullEnable;
195
GLenum cullMode;
196
GLenum frontFace;
197
};
198
199
GLuint ShaderStageToOpenGL(ShaderStage stage) {
200
switch (stage) {
201
case ShaderStage::Vertex: return GL_VERTEX_SHADER;
202
#ifndef USING_GLES2
203
case ShaderStage::Compute: return GL_COMPUTE_SHADER;
204
case ShaderStage::Geometry: return GL_GEOMETRY_SHADER;
205
#endif
206
case ShaderStage::Fragment:
207
default:
208
return GL_FRAGMENT_SHADER;
209
}
210
}
211
212
class OpenGLShaderModule : public ShaderModule {
213
public:
214
OpenGLShaderModule(GLRenderManager *render, ShaderStage stage, const std::string &tag) : render_(render), stage_(stage), tag_(tag) {
215
glstage_ = ShaderStageToOpenGL(stage);
216
}
217
218
~OpenGLShaderModule() {
219
if (shader_)
220
render_->DeleteShader(shader_);
221
}
222
223
bool Compile(GLRenderManager *render, ShaderLanguage language, const uint8_t *data, size_t dataSize);
224
GLRShader *GetShader() const {
225
return shader_;
226
}
227
const std::string &GetSource() const { return source_; }
228
229
ShaderLanguage GetLanguage() {
230
return language_;
231
}
232
ShaderStage GetStage() const override {
233
return stage_;
234
}
235
236
private:
237
GLRenderManager *render_;
238
ShaderStage stage_;
239
ShaderLanguage language_ = GLSL_1xx;
240
GLRShader *shader_ = nullptr;
241
GLuint glstage_ = 0;
242
std::string source_; // So we can recompile in case of context loss.
243
std::string tag_;
244
};
245
246
bool OpenGLShaderModule::Compile(GLRenderManager *render, ShaderLanguage language, const uint8_t *data, size_t dataSize) {
247
source_ = std::string((const char *)data, dataSize);
248
// Add the prelude on automatically.
249
if (glstage_ == GL_FRAGMENT_SHADER || glstage_ == GL_VERTEX_SHADER) {
250
if (source_.find("#version") == std::string::npos) {
251
source_ = ApplyGLSLPrelude(source_, glstage_);
252
}
253
} else {
254
// Unsupported shader type
255
return false;
256
}
257
258
shader_ = render->CreateShader(glstage_, source_, tag_);
259
_assert_(shader_ != nullptr); // normally can't fail since we defer creation, unless there's a memory error or similar.
260
return true;
261
}
262
263
struct PipelineLocData : GLRProgramLocData {
264
GLint samplerLocs_[MAX_TEXTURE_SLOTS]{};
265
std::vector<GLint> dynamicUniformLocs_;
266
};
267
268
class OpenGLInputLayout : public InputLayout {
269
public:
270
OpenGLInputLayout(GLRenderManager *render) : render_(render) {}
271
~OpenGLInputLayout();
272
273
void Compile(const InputLayoutDesc &desc);
274
275
GLRInputLayout *inputLayout_ = nullptr;
276
int stride = 0;
277
private:
278
GLRenderManager *render_;
279
};
280
281
class OpenGLPipeline : public Pipeline {
282
public:
283
OpenGLPipeline(GLRenderManager *render) : render_(render) {}
284
~OpenGLPipeline() {
285
for (auto &iter : shaders) {
286
iter->Release();
287
}
288
if (program_) {
289
render_->DeleteProgram(program_);
290
}
291
// DO NOT delete locs_ here, it's deleted by the render manager.
292
}
293
294
bool LinkShaders(const PipelineDesc &desc);
295
296
GLuint prim = 0;
297
std::vector<OpenGLShaderModule *> shaders;
298
AutoRef<OpenGLInputLayout> inputLayout;
299
AutoRef<OpenGLDepthStencilState> depthStencil;
300
AutoRef<OpenGLBlendState> blend;
301
AutoRef<OpenGLRasterState> raster;
302
303
// Not owned!
304
PipelineLocData *locs_ = nullptr;
305
306
// TODO: Optimize by getting the locations first and putting in a custom struct
307
UniformBufferDesc dynamicUniforms;
308
GLRProgram *program_ = nullptr;
309
310
311
// Allow using other sampler names than sampler0, sampler1 etc in shaders.
312
// If not set, will default to those, though.
313
Slice<SamplerDef> samplers_;
314
315
private:
316
GLRenderManager *render_;
317
};
318
319
class OpenGLFramebuffer;
320
class OpenGLTexture;
321
322
class OpenGLContext : public DrawContext {
323
public:
324
OpenGLContext(bool canChangeSwapInterval);
325
~OpenGLContext();
326
327
BackendState GetCurrentBackendState() const override {
328
return BackendState{
329
(u32)renderManager_.GetNumSteps(),
330
true, // Means that the other value is meaningful.
331
};
332
}
333
334
void SetTargetSize(int w, int h) override {
335
DrawContext::SetTargetSize(w, h);
336
renderManager_.Resize(w, h);
337
}
338
339
const DeviceCaps &GetDeviceCaps() const override {
340
return caps_;
341
}
342
uint32_t GetSupportedShaderLanguages() const override {
343
if (gl_extensions.GLES3) {
344
return (uint32_t)(ShaderLanguage::GLSL_3xx | ShaderLanguage::GLSL_1xx);
345
} else {
346
return (uint32_t)ShaderLanguage::GLSL_1xx;
347
}
348
}
349
350
uint32_t GetDataFormatSupport(DataFormat fmt) const override;
351
352
void SetErrorCallback(ErrorCallbackFn callback, void *userdata) override {
353
renderManager_.SetErrorCallback(callback, userdata);
354
}
355
356
DepthStencilState *CreateDepthStencilState(const DepthStencilStateDesc &desc) override;
357
BlendState *CreateBlendState(const BlendStateDesc &desc) override;
358
SamplerState *CreateSamplerState(const SamplerStateDesc &desc) override;
359
RasterState *CreateRasterState(const RasterStateDesc &desc) override;
360
Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) override;
361
InputLayout *CreateInputLayout(const InputLayoutDesc &desc) override;
362
ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) override;
363
364
Texture *CreateTexture(const TextureDesc &desc) override;
365
Buffer *CreateBuffer(size_t size, uint32_t usageFlags) override;
366
Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override;
367
368
void BeginFrame(DebugFlags debugFlags) override;
369
void EndFrame() override;
370
void Present(PresentMode mode, int vblanks) override;
371
372
int GetFrameCount() override {
373
return frameCount_;
374
}
375
376
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
377
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
378
379
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) override;
380
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) override;
381
bool CopyFramebufferToMemory(Framebuffer *src, Aspect channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) override;
382
383
// These functions should be self explanatory.
384
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
385
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, Aspect channelBit, int layer) override;
386
387
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
388
389
void BindSamplerStates(int start, int count, SamplerState **states) override {
390
_assert_(start + count <= MAX_TEXTURE_SLOTS);
391
for (int i = 0; i < count; i++) {
392
int index = i + start;
393
boundSamplers_[index] = static_cast<OpenGLSamplerState *>(states[i]);
394
}
395
}
396
397
void SetScissorRect(int left, int top, int width, int height) override {
398
renderManager_.SetScissor({ left, top, width, height });
399
}
400
401
void SetViewport(const Viewport &viewport) override {
402
// Same structure, different name.
403
renderManager_.SetViewport((GLRViewport &)viewport);
404
}
405
406
void SetBlendFactor(float color[4]) override {
407
renderManager_.SetBlendFactor(color);
408
}
409
410
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override {
411
stencilRef_ = refValue;
412
stencilWriteMask_ = writeMask;
413
stencilCompareMask_ = compareMask;
414
// Do we need to update on the fly here?
415
renderManager_.SetStencil(
416
curPipeline_->depthStencil->stencilEnabled,
417
curPipeline_->depthStencil->stencilCompareOp,
418
refValue,
419
compareMask,
420
writeMask,
421
curPipeline_->depthStencil->stencilFail,
422
curPipeline_->depthStencil->stencilZFail,
423
curPipeline_->depthStencil->stencilPass);
424
}
425
426
void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override;
427
void BindNativeTexture(int sampler, void *nativeTexture) override;
428
429
void BindPipeline(Pipeline *pipeline) override;
430
void BindVertexBuffer(Buffer *buffer, int offset) override {
431
curVBuffer_ = (OpenGLBuffer *)buffer;
432
curVBufferOffset_ = offset;
433
}
434
void BindIndexBuffer(Buffer *indexBuffer, int offset) override {
435
curIBuffer_ = (OpenGLBuffer *)indexBuffer;
436
curIBufferOffset_ = offset;
437
}
438
439
void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;
440
441
// TODO: Add more sophisticated draws.
442
void Draw(int vertexCount, int offset) override;
443
void DrawIndexed(int vertexCount, int offset) override;
444
void DrawUP(const void *vdata, int vertexCount) override;
445
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override;
446
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) override;
447
448
void Clear(Aspect mask, uint32_t colorval, float depthVal, int stencilVal) override;
449
450
std::string GetInfoString(InfoField info) const override {
451
// TODO: Make these actually query the right information
452
switch (info) {
453
case InfoField::APINAME:
454
if (gl_extensions.IsGLES) {
455
return "OpenGL ES";
456
} else {
457
return "OpenGL";
458
}
459
case InfoField::VENDORSTRING:
460
return renderManager_.GetGLString(GL_VENDOR);
461
case InfoField::VENDOR:
462
switch (caps_.vendor) {
463
case GPUVendor::VENDOR_AMD: return "VENDOR_AMD";
464
case GPUVendor::VENDOR_IMGTEC: return "VENDOR_POWERVR";
465
case GPUVendor::VENDOR_NVIDIA: return "VENDOR_NVIDIA";
466
case GPUVendor::VENDOR_INTEL: return "VENDOR_INTEL";
467
case GPUVendor::VENDOR_QUALCOMM: return "VENDOR_ADRENO";
468
case GPUVendor::VENDOR_ARM: return "VENDOR_ARM";
469
case GPUVendor::VENDOR_BROADCOM: return "VENDOR_BROADCOM";
470
case GPUVendor::VENDOR_VIVANTE: return "VENDOR_VIVANTE";
471
case GPUVendor::VENDOR_APPLE: return "VENDOR_APPLE";
472
case GPUVendor::VENDOR_MESA: return "VENDOR_MESA";
473
case GPUVendor::VENDOR_UNKNOWN:
474
default:
475
return "VENDOR_UNKNOWN";
476
}
477
break;
478
case InfoField::DRIVER: return renderManager_.GetGLString(GL_RENDERER);
479
case InfoField::SHADELANGVERSION: return renderManager_.GetGLString(GL_SHADING_LANGUAGE_VERSION);
480
case InfoField::APIVERSION: return renderManager_.GetGLString(GL_VERSION);
481
default: return "?";
482
}
483
}
484
485
uint64_t GetNativeObject(NativeObject obj, void *srcObject) override;
486
487
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override {}
488
489
void Invalidate(InvalidationFlags flags) override;
490
491
void SetInvalidationCallback(InvalidationCallback callback) override {
492
renderManager_.SetInvalidationCallback(callback);
493
}
494
495
std::string GetGpuProfileString() const override {
496
return renderManager_.GetGpuProfileString();
497
}
498
499
private:
500
void ApplySamplers();
501
502
GLRenderManager renderManager_;
503
int frameCount_ = 0;
504
505
DeviceCaps caps_{};
506
507
// Bound state
508
AutoRef<OpenGLSamplerState> boundSamplers_[MAX_TEXTURE_SLOTS];
509
// Point to GLRTexture directly because they can point to the textures
510
// in framebuffers too (which also can be bound).
511
const GLRTexture *boundTextures_[MAX_TEXTURE_SLOTS]{};
512
513
AutoRef<OpenGLPipeline> curPipeline_;
514
AutoRef<OpenGLBuffer> curVBuffer_;
515
AutoRef<OpenGLBuffer> curIBuffer_;
516
int curVBufferOffset_ = 0;
517
int curIBufferOffset_ = 0;
518
AutoRef<Framebuffer> curRenderTarget_;
519
520
uint8_t stencilRef_ = 0;
521
uint8_t stencilWriteMask_ = 0;
522
uint8_t stencilCompareMask_ = 0;
523
524
// Frames in flight is not such a strict concept as with Vulkan until we start using glBufferStorage and fences.
525
// But might as well have the structure ready, and can't hurt to rotate buffers.
526
struct FrameData {
527
GLPushBuffer *push;
528
};
529
FrameData frameData_[GLRenderManager::MAX_INFLIGHT_FRAMES]{};
530
};
531
532
static constexpr int MakeIntelSimpleVer(int v1, int v2, int v3) {
533
return (v1 << 16) | (v2 << 8) | v3;
534
}
535
536
static bool HasIntelDualSrcBug(const int versions[4]) {
537
// Intel uses a confusing set of at least 3 version numbering schemes. This is the one given to OpenGL.
538
switch (MakeIntelSimpleVer(versions[0], versions[1], versions[2])) {
539
case MakeIntelSimpleVer(9, 17, 10):
540
case MakeIntelSimpleVer(9, 18, 10):
541
return false;
542
case MakeIntelSimpleVer(10, 18, 10):
543
return versions[3] < 4061;
544
case MakeIntelSimpleVer(10, 18, 14):
545
return versions[3] < 4080;
546
default:
547
// Older than above didn't support dual src anyway, newer should have the fix.
548
return false;
549
}
550
}
551
552
OpenGLContext::OpenGLContext(bool canChangeSwapInterval) : renderManager_(frameTimeHistory_) {
553
if (gl_extensions.IsGLES) {
554
if (gl_extensions.OES_packed_depth_stencil || gl_extensions.OES_depth24) {
555
caps_.preferredDepthBufferFormat = DataFormat::D24_S8;
556
} else {
557
caps_.preferredDepthBufferFormat = DataFormat::D16;
558
}
559
if (gl_extensions.GLES3) {
560
// Mali reports 30 but works fine...
561
if (gl_extensions.range[1][5][1] >= 30) {
562
caps_.fragmentShaderInt32Supported = true;
563
}
564
}
565
caps_.texture3DSupported = gl_extensions.OES_texture_3D;
566
caps_.textureDepthSupported = gl_extensions.GLES3 || gl_extensions.OES_depth_texture;
567
} else {
568
if (gl_extensions.VersionGEThan(3, 3, 0)) {
569
caps_.fragmentShaderInt32Supported = true;
570
}
571
caps_.preferredDepthBufferFormat = DataFormat::D24_S8;
572
caps_.texture3DSupported = true;
573
caps_.textureDepthSupported = true;
574
}
575
576
caps_.coordConvention = CoordConvention::OpenGL;
577
caps_.setMaxFrameLatencySupported = true;
578
caps_.dualSourceBlend = gl_extensions.ARB_blend_func_extended || gl_extensions.EXT_blend_func_extended;
579
caps_.anisoSupported = gl_extensions.EXT_texture_filter_anisotropic;
580
caps_.framebufferCopySupported = gl_extensions.OES_copy_image || gl_extensions.NV_copy_image || gl_extensions.EXT_copy_image || gl_extensions.ARB_copy_image;
581
caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3;
582
caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported;
583
caps_.framebufferStencilBlitSupported = caps_.framebufferBlitSupported;
584
caps_.depthClampSupported = gl_extensions.ARB_depth_clamp || gl_extensions.EXT_depth_clamp;
585
caps_.blendMinMaxSupported = gl_extensions.EXT_blend_minmax;
586
caps_.multiSampleLevelsMask = 1; // More could be supported with some work.
587
588
if (gl_extensions.IsGLES) {
589
caps_.clipDistanceSupported = gl_extensions.EXT_clip_cull_distance || gl_extensions.APPLE_clip_distance;
590
caps_.cullDistanceSupported = gl_extensions.EXT_clip_cull_distance;
591
} else {
592
caps_.clipDistanceSupported = gl_extensions.VersionGEThan(3, 0);
593
caps_.cullDistanceSupported = gl_extensions.ARB_cull_distance;
594
}
595
caps_.textureNPOTFullySupported =
596
(!gl_extensions.IsGLES && gl_extensions.VersionGEThan(2, 0, 0)) ||
597
gl_extensions.IsCoreContext || gl_extensions.GLES3 ||
598
gl_extensions.ARB_texture_non_power_of_two || gl_extensions.OES_texture_npot;
599
600
if (gl_extensions.IsGLES) {
601
caps_.fragmentShaderDepthWriteSupported = gl_extensions.GLES3;
602
// There's also GL_EXT_frag_depth but it's rare along with 2.0. Most chips that support it are simply 3.0 chips.
603
} else {
604
caps_.fragmentShaderDepthWriteSupported = true;
605
}
606
caps_.fragmentShaderStencilWriteSupported = gl_extensions.ARB_shader_stencil_export;
607
608
// GLES has no support for logic framebuffer operations. There doesn't even seem to exist any such extensions.
609
caps_.logicOpSupported = !gl_extensions.IsGLES;
610
611
// Always the case in GL (which is what we want for PSP flat shade).
612
caps_.provokingVertexLast = true;
613
614
// Interesting potential hack for emulating GL_DEPTH_CLAMP (use a separate varying, force depth in fragment shader):
615
// This will induce a performance penalty on many architectures though so a blanket enable of this
616
// is probably not a good idea.
617
// https://stackoverflow.com/questions/5960757/how-to-emulate-gl-depth-clamp-nv
618
619
switch (gl_extensions.gpuVendor) {
620
case GPU_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break;
621
case GPU_VENDOR_NVIDIA: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break;
622
case GPU_VENDOR_ARM: caps_.vendor = GPUVendor::VENDOR_ARM; break;
623
case GPU_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::VENDOR_QUALCOMM; break;
624
case GPU_VENDOR_BROADCOM: caps_.vendor = GPUVendor::VENDOR_BROADCOM; break;
625
case GPU_VENDOR_INTEL: caps_.vendor = GPUVendor::VENDOR_INTEL; break;
626
case GPU_VENDOR_IMGTEC: caps_.vendor = GPUVendor::VENDOR_IMGTEC; break;
627
case GPU_VENDOR_VIVANTE: caps_.vendor = GPUVendor::VENDOR_VIVANTE; break;
628
case GPU_VENDOR_APPLE: caps_.vendor = GPUVendor::VENDOR_APPLE; break;
629
case GPU_VENDOR_MESA: caps_.vendor = GPUVendor::VENDOR_MESA; break;
630
case GPU_VENDOR_UNKNOWN:
631
default:
632
caps_.vendor = GPUVendor::VENDOR_UNKNOWN;
633
break;
634
}
635
636
// Very rough heuristic!
637
caps_.isTilingGPU = gl_extensions.IsGLES && caps_.vendor != GPUVendor::VENDOR_NVIDIA && caps_.vendor != GPUVendor::VENDOR_INTEL;
638
639
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
640
frameData_[i].push = renderManager_.CreatePushBuffer(i, GL_ARRAY_BUFFER, 64 * 1024, "thin3d_vbuf");
641
}
642
643
if (!gl_extensions.VersionGEThan(3, 0, 0)) {
644
// Don't use this extension on sub 3.0 OpenGL versions as it does not seem reliable.
645
bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN);
646
} else if (caps_.vendor == GPUVendor::VENDOR_INTEL) {
647
// Note: this is for Intel drivers with GL3+.
648
// Also on Intel, see https://github.com/hrydgard/ppsspp/issues/10117
649
// TODO: Remove entirely sometime reasonably far in driver years after 2015.
650
const std::string ver = OpenGLContext::GetInfoString(Draw::InfoField::APIVERSION);
651
int versions[4]{};
652
if (sscanf(ver.c_str(), "Build %d.%d.%d.%d", &versions[0], &versions[1], &versions[2], &versions[3]) == 4) {
653
if (HasIntelDualSrcBug(versions)) {
654
bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN);
655
}
656
}
657
}
658
659
#if PPSSPP_ARCH(ARMV7)
660
if (caps_.vendor == GPUVendor::VENDOR_BROADCOM) {
661
bugs_.Infest(Bugs::RASPBERRY_SHADER_COMP_HANG);
662
}
663
#endif
664
665
// Try to detect old Tegra chips by checking for sub 3.0 GL versions. Like Vivante and Broadcom,
666
// those can't handle NaN values in conditionals.
667
if (caps_.vendor == GPUVendor::VENDOR_VIVANTE ||
668
caps_.vendor == GPUVendor::VENDOR_BROADCOM ||
669
(caps_.vendor == GPUVendor::VENDOR_NVIDIA && !gl_extensions.VersionGEThan(3, 0, 0))) {
670
bugs_.Infest(Bugs::BROKEN_NAN_IN_CONDITIONAL);
671
}
672
673
// TODO: Make this check more lenient. Disabled for all right now
674
// because it murders performance on Mali.
675
if (caps_.vendor != GPUVendor::VENDOR_NVIDIA) {
676
bugs_.Infest(Bugs::ANY_MAP_BUFFER_RANGE_SLOW);
677
}
678
679
if (caps_.vendor == GPUVendor::VENDOR_IMGTEC) {
680
// See https://github.com/hrydgard/ppsspp/commit/8974cd675e538f4445955e3eac572a9347d84232
681
// TODO: Should this workaround be removed for newer devices/drivers?
682
bugs_.Infest(Bugs::PVR_GENMIPMAP_HEIGHT_GREATER);
683
}
684
685
if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) {
686
#if PPSSPP_PLATFORM(ANDROID)
687
// The bug seems to affect Adreno 3xx and 5xx, and appeared in Android 8.0 Oreo, so API 26.
688
// See https://github.com/hrydgard/ppsspp/issues/16015#issuecomment-1328316080.
689
if (gl_extensions.modelNumber < 600 && System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 26)
690
bugs_.Infest(Bugs::ADRENO_RESOURCE_DEADLOCK);
691
#endif
692
}
693
694
#if PPSSPP_PLATFORM(IOS)
695
// For some reason, this bug does not appear on M1.
696
if (caps_.vendor == GPUVendor::VENDOR_APPLE) {
697
bugs_.Infest(Bugs::BROKEN_FLAT_IN_SHADER);
698
}
699
#endif
700
701
shaderLanguageDesc_.Init(GLSL_1xx);
702
703
shaderLanguageDesc_.glslVersionNumber = gl_extensions.GLSLVersion();
704
705
snprintf(shaderLanguageDesc_.driverInfo, sizeof(shaderLanguageDesc_.driverInfo),
706
"%s - GLSL %d", gl_extensions.model, gl_extensions.GLSLVersion());
707
// Detect shader language features.
708
if (gl_extensions.IsGLES) {
709
shaderLanguageDesc_.gles = true;
710
if (gl_extensions.GLES3) {
711
shaderLanguageDesc_.shaderLanguage = ShaderLanguage::GLSL_3xx;
712
shaderLanguageDesc_.fragColor0 = "fragColor0";
713
shaderLanguageDesc_.texture = "texture";
714
shaderLanguageDesc_.texture3D = "texture";
715
shaderLanguageDesc_.glslES30 = true;
716
shaderLanguageDesc_.bitwiseOps = true;
717
shaderLanguageDesc_.texelFetch = "texelFetch";
718
shaderLanguageDesc_.varying_vs = "out";
719
shaderLanguageDesc_.varying_fs = "in";
720
shaderLanguageDesc_.attribute = "in";
721
} else {
722
shaderLanguageDesc_.shaderLanguage = ShaderLanguage::GLSL_1xx;
723
if (gl_extensions.EXT_gpu_shader4) {
724
shaderLanguageDesc_.bitwiseOps = true;
725
shaderLanguageDesc_.texelFetch = "texelFetch2D";
726
}
727
if (gl_extensions.EXT_blend_func_extended) {
728
// Oldy moldy GLES, so use the fixed output name.
729
shaderLanguageDesc_.fragColor1 = "gl_SecondaryFragColorEXT";
730
}
731
}
732
} else {
733
// I don't know why we were checking for IsCoreContext here before.
734
if (gl_extensions.VersionGEThan(3, 3, 0)) {
735
shaderLanguageDesc_.shaderLanguage = ShaderLanguage::GLSL_3xx;
736
shaderLanguageDesc_.fragColor0 = "fragColor0";
737
shaderLanguageDesc_.texture = "texture";
738
shaderLanguageDesc_.texture3D = "texture";
739
shaderLanguageDesc_.glslES30 = true;
740
shaderLanguageDesc_.bitwiseOps = true;
741
shaderLanguageDesc_.texelFetch = "texelFetch";
742
shaderLanguageDesc_.varying_vs = "out";
743
shaderLanguageDesc_.varying_fs = "in";
744
shaderLanguageDesc_.attribute = "in";
745
} else if (gl_extensions.VersionGEThan(3, 0, 0)) {
746
shaderLanguageDesc_.shaderLanguage = ShaderLanguage::GLSL_1xx;
747
shaderLanguageDesc_.fragColor0 = "fragColor0";
748
shaderLanguageDesc_.texture = "texture";
749
shaderLanguageDesc_.texture3D = "texture";
750
shaderLanguageDesc_.bitwiseOps = true;
751
shaderLanguageDesc_.texelFetch = "texelFetch";
752
shaderLanguageDesc_.varying_vs = "out";
753
shaderLanguageDesc_.varying_fs = "in";
754
shaderLanguageDesc_.attribute = "in";
755
} else {
756
// This too...
757
shaderLanguageDesc_.shaderLanguage = ShaderLanguage::GLSL_1xx;
758
if (gl_extensions.EXT_gpu_shader4) {
759
// Older macOS devices seem to have problems defining uint uniforms.
760
// Let's just assume OpenGL 3.0+ is required.
761
shaderLanguageDesc_.bitwiseOps = gl_extensions.VersionGEThan(3, 0, 0);
762
shaderLanguageDesc_.texelFetch = "texelFetch2D";
763
}
764
}
765
}
766
767
// NOTE: We only support framebuffer fetch on ES3 due to past issues..
768
if (gl_extensions.IsGLES && gl_extensions.GLES3) {
769
caps_.framebufferFetchSupported = (gl_extensions.EXT_shader_framebuffer_fetch || gl_extensions.ARM_shader_framebuffer_fetch);
770
771
if (gl_extensions.EXT_shader_framebuffer_fetch) {
772
shaderLanguageDesc_.framebufferFetchExtension = "#extension GL_EXT_shader_framebuffer_fetch : require";
773
shaderLanguageDesc_.lastFragData = "fragColor0";
774
} else if (gl_extensions.ARM_shader_framebuffer_fetch) {
775
shaderLanguageDesc_.framebufferFetchExtension = "#extension GL_ARM_shader_framebuffer_fetch : require";
776
shaderLanguageDesc_.lastFragData = "gl_LastFragColorARM";
777
}
778
}
779
780
if (canChangeSwapInterval) {
781
caps_.presentInstantModeChange = true;
782
caps_.presentMaxInterval = 4;
783
caps_.presentModesSupported = PresentMode::FIFO | PresentMode::IMMEDIATE;
784
} else {
785
caps_.presentInstantModeChange = false;
786
caps_.presentModesSupported = PresentMode::FIFO;
787
caps_.presentMaxInterval = 1;
788
}
789
790
renderManager_.SetDeviceCaps(caps_);
791
}
792
793
OpenGLContext::~OpenGLContext() {
794
DestroyPresets();
795
796
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
797
renderManager_.DeletePushBuffer(frameData_[i].push);
798
}
799
}
800
801
void OpenGLContext::BeginFrame(DebugFlags debugFlags) {
802
renderManager_.BeginFrame(debugFlags & DebugFlags::PROFILE_TIMESTAMPS);
803
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
804
frameData.push->Begin();
805
}
806
807
void OpenGLContext::EndFrame() {
808
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
809
frameData.push->End(); // upload the data!
810
renderManager_.Finish();
811
Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
812
}
813
814
void OpenGLContext::Present(PresentMode presentMode, int vblanks) {
815
renderManager_.Present();
816
frameCount_++;
817
}
818
819
void OpenGLContext::Invalidate(InvalidationFlags flags) {
820
if (flags & InvalidationFlags::CACHED_RENDER_STATE) {
821
// Unbind stuff.
822
for (auto &texture : boundTextures_) {
823
texture = nullptr;
824
}
825
for (auto &sampler : boundSamplers_) {
826
sampler = nullptr;
827
}
828
curPipeline_ = nullptr;
829
}
830
}
831
832
InputLayout *OpenGLContext::CreateInputLayout(const InputLayoutDesc &desc) {
833
OpenGLInputLayout *fmt = new OpenGLInputLayout(&renderManager_);
834
fmt->Compile(desc);
835
return fmt;
836
}
837
838
static GLuint TypeToTarget(TextureType type) {
839
switch (type) {
840
#ifndef USING_GLES2
841
case TextureType::LINEAR1D: return GL_TEXTURE_1D;
842
#endif
843
case TextureType::LINEAR2D: return GL_TEXTURE_2D;
844
case TextureType::LINEAR3D: return GL_TEXTURE_3D;
845
case TextureType::CUBE: return GL_TEXTURE_CUBE_MAP;
846
#ifndef USING_GLES2
847
case TextureType::ARRAY1D: return GL_TEXTURE_1D_ARRAY;
848
#endif
849
case TextureType::ARRAY2D: return GL_TEXTURE_2D_ARRAY;
850
default:
851
ERROR_LOG(Log::G3D, "Bad texture type %d", (int)type);
852
return GL_NONE;
853
}
854
}
855
856
class OpenGLTexture : public Texture {
857
public:
858
OpenGLTexture(GLRenderManager *render, const TextureDesc &desc);
859
~OpenGLTexture();
860
861
bool HasMips() const {
862
return mipLevels_ > 1 || generatedMips_;
863
}
864
865
TextureType GetType() const { return type_; }
866
void Bind(int stage) {
867
render_->BindTexture(stage, tex_);
868
}
869
int NumMipmaps() const {
870
return mipLevels_;
871
}
872
GLRTexture *GetTex() const {
873
return tex_;
874
}
875
876
void UpdateTextureLevels(GLRenderManager *render, const uint8_t *const *data, int numLevels, TextureCallback initDataCallback);
877
878
private:
879
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback initDataCallback);
880
881
GLRenderManager *render_;
882
GLRTexture *tex_;
883
884
TextureType type_;
885
int mipLevels_;
886
bool generateMips_; // Generate mips requested
887
bool generatedMips_; // Has generated mips
888
};
889
890
OpenGLTexture::OpenGLTexture(GLRenderManager *render, const TextureDesc &desc) : render_(render) {
891
_dbg_assert_(desc.format != Draw::DataFormat::UNDEFINED);
892
_dbg_assert_msg_(desc.width > 0 && desc.height > 0 && desc.depth > 0, "w: %d h: %d d: %d fmt: %s", desc.width, desc.height, desc.depth, DataFormatToString(desc.format));
893
_dbg_assert_(desc.width > 0 && desc.height > 0 && desc.depth > 0);
894
_dbg_assert_(desc.type != Draw::TextureType::UNKNOWN);
895
896
generatedMips_ = false;
897
generateMips_ = desc.generateMips;
898
width_ = desc.width;
899
height_ = desc.height;
900
depth_ = desc.depth;
901
format_ = desc.format;
902
type_ = desc.type;
903
904
GLenum target = TypeToTarget(desc.type);
905
tex_ = render->CreateTexture(target, desc.width, desc.height, 1, desc.mipLevels);
906
907
mipLevels_ = desc.mipLevels;
908
if (desc.initData.empty())
909
return;
910
911
UpdateTextureLevels(render, desc.initData.data(), (int)desc.initData.size(), desc.initDataCallback);
912
}
913
914
void OpenGLTexture::UpdateTextureLevels(GLRenderManager *render, const uint8_t * const *data, int numLevels, TextureCallback initDataCallback) {
915
int level = 0;
916
int width = width_;
917
int height = height_;
918
int depth = depth_;
919
for (int i = 0; i < numLevels; i++) {
920
SetImageData(0, 0, 0, width, height, depth, level, 0, data[i], initDataCallback);
921
width = (width + 1) / 2;
922
height = (height + 1) / 2;
923
depth = (depth + 1) / 2;
924
level++;
925
}
926
mipLevels_ = generateMips_ ? mipLevels_ : level;
927
928
bool genMips = false;
929
if (numLevels < mipLevels_ && generateMips_) {
930
// Assumes the texture is bound for editing
931
genMips = true;
932
generatedMips_ = true;
933
}
934
render->FinalizeTexture(tex_, mipLevels_, genMips);
935
}
936
937
OpenGLTexture::~OpenGLTexture() {
938
if (tex_) {
939
render_->DeleteTexture(tex_);
940
tex_ = nullptr;
941
generatedMips_ = false;
942
}
943
}
944
945
class OpenGLFramebuffer : public Framebuffer {
946
public:
947
OpenGLFramebuffer(GLRenderManager *render, GLRFramebuffer *framebuffer) : render_(render), framebuffer_(framebuffer) {
948
width_ = framebuffer->width;
949
height_ = framebuffer->height;
950
}
951
~OpenGLFramebuffer() {
952
render_->DeleteFramebuffer(framebuffer_);
953
}
954
955
GLRenderManager *render_;
956
GLRFramebuffer *framebuffer_ = nullptr;
957
};
958
959
void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback initDataCallback) {
960
if ((width != width_ || height != height_ || depth != depth_) && level == 0) {
961
// When switching to texStorage we need to handle this correctly.
962
width_ = width;
963
height_ = height;
964
depth_ = depth;
965
}
966
967
if (!stride)
968
stride = width;
969
970
size_t alignment = DataFormatSizeInBytes(format_);
971
// Make a copy of data with stride eliminated.
972
uint8_t *texData = new uint8_t[(size_t)(width * height * depth * alignment)];
973
974
bool texDataPopulated = false;
975
if (initDataCallback) {
976
texDataPopulated = initDataCallback(texData, data, width, height, depth, width * (int)alignment, height * width * (int)alignment);
977
}
978
if (texDataPopulated) {
979
if (format_ == DataFormat::A1R5G5B5_UNORM_PACK16) {
980
format_ = DataFormat::R5G5B5A1_UNORM_PACK16;
981
ConvertBGRA5551ToABGR1555((u16 *)texData, (const u16 *)texData, width * height * depth);
982
}
983
} else {
984
// Emulate support for DataFormat::A1R5G5B5_UNORM_PACK16.
985
if (format_ == DataFormat::A1R5G5B5_UNORM_PACK16) {
986
format_ = DataFormat::R5G5B5A1_UNORM_PACK16;
987
for (int y = 0; y < height; y++) {
988
ConvertBGRA5551ToABGR1555((u16 *)(texData + y * width * alignment), (const u16 *)(data + y * stride * alignment), width);
989
}
990
} else {
991
for (int y = 0; y < height; y++) {
992
memcpy(texData + y * width * alignment, data + y * stride * alignment, width * alignment);
993
}
994
}
995
}
996
997
render_->TextureImage(tex_, level, width, height, depth, format_, texData);
998
}
999
1000
#ifdef DEBUG_READ_PIXELS
1001
// TODO: Make more generic.
1002
static void LogReadPixelsError(GLenum error) {
1003
switch (error) {
1004
case GL_NO_ERROR:
1005
break;
1006
case GL_INVALID_ENUM:
1007
ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_ENUM");
1008
break;
1009
case GL_INVALID_VALUE:
1010
ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_VALUE");
1011
break;
1012
case GL_INVALID_OPERATION:
1013
ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_OPERATION");
1014
break;
1015
case GL_INVALID_FRAMEBUFFER_OPERATION:
1016
ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION");
1017
break;
1018
case GL_OUT_OF_MEMORY:
1019
ERROR_LOG(Log::G3D, "glReadPixels: GL_OUT_OF_MEMORY");
1020
break;
1021
#ifndef USING_GLES2
1022
case GL_STACK_UNDERFLOW:
1023
ERROR_LOG(Log::G3D, "glReadPixels: GL_STACK_UNDERFLOW");
1024
break;
1025
case GL_STACK_OVERFLOW:
1026
ERROR_LOG(Log::G3D, "glReadPixels: GL_STACK_OVERFLOW");
1027
break;
1028
#endif
1029
default:
1030
ERROR_LOG(Log::G3D, "glReadPixels: %08x", error);
1031
break;
1032
}
1033
}
1034
#endif
1035
1036
bool OpenGLContext::CopyFramebufferToMemory(Framebuffer *src, Aspect channelBits, int x, int y, int w, int h, Draw::DataFormat dataFormat, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) {
1037
if (gl_extensions.IsGLES && (channelBits & Aspect::COLOR_BIT) == 0) {
1038
// Can't readback depth or stencil on GLES.
1039
return false;
1040
}
1041
OpenGLFramebuffer *fb = (OpenGLFramebuffer *)src;
1042
GLuint aspect = 0;
1043
if (channelBits & Aspect::COLOR_BIT)
1044
aspect |= GL_COLOR_BUFFER_BIT;
1045
if (channelBits & Aspect::DEPTH_BIT)
1046
aspect |= GL_DEPTH_BUFFER_BIT;
1047
if (channelBits & Aspect::STENCIL_BIT)
1048
aspect |= GL_STENCIL_BUFFER_BIT;
1049
return renderManager_.CopyFramebufferToMemory(fb ? fb->framebuffer_ : nullptr, aspect, x, y, w, h, dataFormat, (uint8_t *)pixels, pixelStride, mode, tag);
1050
}
1051
1052
1053
Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) {
1054
return new OpenGLTexture(&renderManager_, desc);
1055
}
1056
1057
void OpenGLContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {
1058
OpenGLTexture *tex = (OpenGLTexture *)texture;
1059
tex->UpdateTextureLevels(&renderManager_, data, numLevels, initDataCallback);
1060
}
1061
1062
DepthStencilState *OpenGLContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
1063
OpenGLDepthStencilState *ds = new OpenGLDepthStencilState();
1064
ds->depthTestEnabled = desc.depthTestEnabled;
1065
ds->depthWriteEnabled = desc.depthWriteEnabled;
1066
ds->depthComp = compToGL[(int)desc.depthCompare];
1067
ds->stencilEnabled = desc.stencilEnabled;
1068
ds->stencilCompareOp = compToGL[(int)desc.stencil.compareOp];
1069
ds->stencilPass = stencilOpToGL[(int)desc.stencil.passOp];
1070
ds->stencilFail = stencilOpToGL[(int)desc.stencil.failOp];
1071
ds->stencilZFail = stencilOpToGL[(int)desc.stencil.depthFailOp];
1072
return ds;
1073
}
1074
1075
BlendState *OpenGLContext::CreateBlendState(const BlendStateDesc &desc) {
1076
OpenGLBlendState *bs = new OpenGLBlendState();
1077
bs->enabled = desc.enabled;
1078
bs->eqCol = blendEqToGL[(int)desc.eqCol];
1079
bs->srcCol = blendFactorToGL[(int)desc.srcCol];
1080
bs->dstCol = blendFactorToGL[(int)desc.dstCol];
1081
bs->eqAlpha = blendEqToGL[(int)desc.eqAlpha];
1082
bs->srcAlpha = blendFactorToGL[(int)desc.srcAlpha];
1083
bs->dstAlpha = blendFactorToGL[(int)desc.dstAlpha];
1084
bs->colorMask = desc.colorMask;
1085
return bs;
1086
}
1087
1088
SamplerState *OpenGLContext::CreateSamplerState(const SamplerStateDesc &desc) {
1089
OpenGLSamplerState *samps = new OpenGLSamplerState();
1090
samps->wrapU = texWrapToGL[(int)desc.wrapU];
1091
samps->wrapV = texWrapToGL[(int)desc.wrapV];
1092
samps->wrapW = texWrapToGL[(int)desc.wrapW];
1093
samps->magFilt = texFilterToGL[(int)desc.magFilter];
1094
samps->minFilt = texFilterToGL[(int)desc.minFilter];
1095
samps->mipMinFilt = texMipFilterToGL[(int)desc.minFilter][(int)desc.mipFilter];
1096
return samps;
1097
}
1098
1099
RasterState *OpenGLContext::CreateRasterState(const RasterStateDesc &desc) {
1100
OpenGLRasterState *rs = new OpenGLRasterState();
1101
if (desc.cull == CullMode::NONE) {
1102
rs->cullEnable = GL_FALSE;
1103
return rs;
1104
}
1105
rs->cullEnable = GL_TRUE;
1106
switch (desc.frontFace) {
1107
case Facing::CW:
1108
rs->frontFace = GL_CW;
1109
break;
1110
case Facing::CCW:
1111
rs->frontFace = GL_CCW;
1112
break;
1113
}
1114
switch (desc.cull) {
1115
case CullMode::FRONT:
1116
rs->cullMode = GL_FRONT;
1117
break;
1118
case CullMode::BACK:
1119
rs->cullMode = GL_BACK;
1120
break;
1121
case CullMode::FRONT_AND_BACK:
1122
rs->cullMode = GL_FRONT_AND_BACK;
1123
break;
1124
case CullMode::NONE:
1125
// Unsupported
1126
break;
1127
}
1128
return rs;
1129
}
1130
1131
class OpenGLBuffer : public Buffer {
1132
public:
1133
OpenGLBuffer(GLRenderManager *render, size_t size, uint32_t flags) : render_(render) {
1134
target_ = (flags & BufferUsageFlag::INDEXDATA) ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
1135
usage_ = 0;
1136
if (flags & BufferUsageFlag::DYNAMIC)
1137
usage_ = GL_STREAM_DRAW;
1138
else
1139
usage_ = GL_STATIC_DRAW;
1140
buffer_ = render->CreateBuffer(target_, size, usage_);
1141
totalSize_ = size;
1142
}
1143
~OpenGLBuffer() {
1144
render_->DeleteBuffer(buffer_);
1145
}
1146
1147
GLRenderManager *render_;
1148
GLRBuffer *buffer_;
1149
GLuint target_;
1150
GLuint usage_;
1151
1152
size_t totalSize_;
1153
};
1154
1155
Buffer *OpenGLContext::CreateBuffer(size_t size, uint32_t usageFlags) {
1156
return new OpenGLBuffer(&renderManager_, size, usageFlags);
1157
}
1158
1159
void OpenGLContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) {
1160
OpenGLBuffer *buf = (OpenGLBuffer *)buffer;
1161
1162
if (size + offset > buf->totalSize_) {
1163
Crash();
1164
}
1165
1166
uint8_t *dataCopy = new uint8_t[size];
1167
memcpy(dataCopy, data, size);
1168
// if (flags & UPDATE_DISCARD) we could try to orphan the buffer using glBufferData.
1169
// But we're much better off using separate buffers per FrameData...
1170
renderManager_.BufferSubdata(buf->buffer_, offset, size, dataCopy);
1171
}
1172
1173
Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) {
1174
if (!desc.shaders.size()) {
1175
ERROR_LOG(Log::G3D, "Pipeline requires at least one shader");
1176
return nullptr;
1177
}
1178
if ((uint32_t)desc.prim >= (uint32_t)Primitive::PRIMITIVE_TYPE_COUNT) {
1179
ERROR_LOG(Log::G3D, "Invalid primitive type");
1180
return nullptr;
1181
}
1182
if (!desc.depthStencil || !desc.blend || !desc.raster) {
1183
ERROR_LOG(Log::G3D, "Incomplete prim desciption");
1184
return nullptr;
1185
}
1186
1187
OpenGLPipeline *pipeline = new OpenGLPipeline(&renderManager_);
1188
for (auto iter : desc.shaders) {
1189
if (iter) {
1190
iter->AddRef();
1191
pipeline->shaders.push_back(static_cast<OpenGLShaderModule *>(iter));
1192
} else {
1193
ERROR_LOG(Log::G3D, "ERROR: Tried to create graphics pipeline %s with a null shader module", tag ? tag : "no tag");
1194
delete pipeline;
1195
return nullptr;
1196
}
1197
}
1198
1199
if (desc.uniformDesc) {
1200
pipeline->dynamicUniforms = *desc.uniformDesc;
1201
}
1202
1203
pipeline->samplers_ = desc.samplers;
1204
if (pipeline->LinkShaders(desc)) {
1205
_assert_((u32)desc.prim < ARRAY_SIZE(primToGL));
1206
// Build the rest of the virtual pipeline object.
1207
pipeline->prim = primToGL[(int)desc.prim];
1208
pipeline->depthStencil = (OpenGLDepthStencilState *)desc.depthStencil;
1209
pipeline->blend = (OpenGLBlendState *)desc.blend;
1210
pipeline->raster = (OpenGLRasterState *)desc.raster;
1211
pipeline->inputLayout = (OpenGLInputLayout *)desc.inputLayout;
1212
return pipeline;
1213
} else {
1214
ERROR_LOG(Log::G3D, "Failed to create pipeline %s - shaders failed to link", tag ? tag : "no tag");
1215
delete pipeline;
1216
return nullptr;
1217
}
1218
}
1219
1220
void OpenGLContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) {
1221
_assert_(start + count <= MAX_TEXTURE_SLOTS);
1222
for (int i = start; i < start + count; i++) {
1223
OpenGLTexture *glTex = static_cast<OpenGLTexture *>(textures[i - start]);
1224
if (!glTex) {
1225
boundTextures_[i] = nullptr;
1226
renderManager_.BindTexture(i, nullptr);
1227
continue;
1228
}
1229
glTex->Bind(i);
1230
boundTextures_[i] = glTex->GetTex();
1231
}
1232
}
1233
1234
void OpenGLContext::BindNativeTexture(int index, void *nativeTexture) {
1235
GLRTexture *tex = (GLRTexture *)nativeTexture;
1236
boundTextures_[index] = tex;
1237
renderManager_.BindTexture(index, tex);
1238
}
1239
1240
void OpenGLContext::ApplySamplers() {
1241
for (int i = 0; i < MAX_TEXTURE_SLOTS; i++) {
1242
const OpenGLSamplerState *samp = boundSamplers_[i];
1243
const GLRTexture *tex = boundTextures_[i];
1244
if (tex) {
1245
_assert_msg_(samp, "Sampler missing");
1246
} else {
1247
continue;
1248
}
1249
GLenum wrapS;
1250
GLenum wrapT;
1251
if (tex->canWrap) {
1252
wrapS = samp->wrapU;
1253
wrapT = samp->wrapV;
1254
} else {
1255
wrapS = GL_CLAMP_TO_EDGE;
1256
wrapT = GL_CLAMP_TO_EDGE;
1257
}
1258
GLenum magFilt = samp->magFilt;
1259
GLenum minFilt = tex->numMips > 1 ? samp->mipMinFilt : samp->minFilt;
1260
renderManager_.SetTextureSampler(i, wrapS, wrapT, magFilt, minFilt, 0.0f);
1261
renderManager_.SetTextureLod(i, 0.0, (float)(tex->numMips - 1), 0.0);
1262
}
1263
}
1264
1265
ShaderModule *OpenGLContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) {
1266
OpenGLShaderModule *shader = new OpenGLShaderModule(&renderManager_, stage, tag);
1267
if (shader->Compile(&renderManager_, language, data, dataSize)) {
1268
return shader;
1269
} else {
1270
shader->Release();
1271
return nullptr;
1272
}
1273
}
1274
1275
bool OpenGLPipeline::LinkShaders(const PipelineDesc &desc) {
1276
std::vector<GLRShader *> linkShaders;
1277
for (auto shaderModule : shaders) {
1278
if (shaderModule) {
1279
GLRShader *shader = shaderModule->GetShader();
1280
if (shader) {
1281
linkShaders.push_back(shader);
1282
} else {
1283
ERROR_LOG(Log::G3D, "LinkShaders: Bad shader module");
1284
return false;
1285
}
1286
} else {
1287
ERROR_LOG(Log::G3D, "LinkShaders: Bad shader in module");
1288
return false;
1289
}
1290
}
1291
1292
std::vector<GLRProgram::Semantic> semantics;
1293
semantics.reserve(8);
1294
// Bind all the common vertex data points. Mismatching ones will be ignored.
1295
semantics.push_back({ SEM_POSITION, "Position" });
1296
semantics.push_back({ SEM_COLOR0, "Color0" });
1297
semantics.push_back({ SEM_COLOR1, "Color1" });
1298
semantics.push_back({ SEM_TEXCOORD0, "TexCoord0" });
1299
semantics.push_back({ SEM_NORMAL, "Normal" });
1300
semantics.push_back({ SEM_TANGENT, "Tangent" });
1301
semantics.push_back({ SEM_BINORMAL, "Binormal" });
1302
// For postshaders.
1303
semantics.push_back({ SEM_POSITION, "a_position" });
1304
semantics.push_back({ SEM_TEXCOORD0, "a_texcoord0" });
1305
1306
locs_ = new PipelineLocData();
1307
locs_->dynamicUniformLocs_.resize(desc.uniformDesc->uniforms.size());
1308
1309
std::vector<GLRProgram::UniformLocQuery> queries;
1310
int samplersToCheck;
1311
if (!samplers_.is_empty()) {
1312
int size = std::min((const uint32_t)samplers_.size(), MAX_TEXTURE_SLOTS);
1313
queries.reserve(size);
1314
for (int i = 0; i < size; i++) {
1315
queries.push_back({ &locs_->samplerLocs_[i], samplers_[i].name, true });
1316
}
1317
samplersToCheck = size;
1318
} else {
1319
queries.push_back({ &locs_->samplerLocs_[0], "sampler0" });
1320
queries.push_back({ &locs_->samplerLocs_[1], "sampler1" });
1321
queries.push_back({ &locs_->samplerLocs_[2], "sampler2" });
1322
samplersToCheck = 3;
1323
}
1324
1325
_assert_(queries.size() <= MAX_TEXTURE_SLOTS);
1326
queries.reserve(dynamicUniforms.uniforms.size());
1327
for (size_t i = 0; i < dynamicUniforms.uniforms.size(); ++i) {
1328
queries.push_back({ &locs_->dynamicUniformLocs_[i], dynamicUniforms.uniforms[i].name });
1329
}
1330
std::vector<GLRProgram::Initializer> initialize;
1331
for (int i = 0; i < MAX_TEXTURE_SLOTS; ++i) {
1332
if (i < samplersToCheck) {
1333
initialize.push_back({ &locs_->samplerLocs_[i], 0, i });
1334
} else {
1335
locs_->samplerLocs_[i] = -1;
1336
}
1337
}
1338
1339
GLRProgramFlags flags{};
1340
program_ = render_->CreateProgram(linkShaders, semantics, queries, initialize, locs_, flags);
1341
return true;
1342
}
1343
1344
void OpenGLContext::BindPipeline(Pipeline *pipeline) {
1345
curPipeline_ = (OpenGLPipeline *)pipeline;
1346
if (!curPipeline_) {
1347
return;
1348
}
1349
curPipeline_->blend->Apply(&renderManager_);
1350
curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
1351
curPipeline_->raster->Apply(&renderManager_);
1352
renderManager_.BindProgram(curPipeline_->program_);
1353
}
1354
1355
void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
1356
if (curPipeline_->dynamicUniforms.uniformBufferSize != size) {
1357
Crash();
1358
}
1359
1360
for (size_t i = 0; i < curPipeline_->dynamicUniforms.uniforms.size(); ++i) {
1361
const auto &uniform = curPipeline_->dynamicUniforms.uniforms[i];
1362
const GLint &loc = curPipeline_->locs_->dynamicUniformLocs_[i];
1363
const float *data = (const float *)((uint8_t *)ub + uniform.offset);
1364
switch (uniform.type) {
1365
case UniformType::FLOAT1:
1366
case UniformType::FLOAT2:
1367
case UniformType::FLOAT3:
1368
case UniformType::FLOAT4:
1369
renderManager_.SetUniformF(&loc, 1 + (int)uniform.type - (int)UniformType::FLOAT1, data);
1370
break;
1371
case UniformType::MATRIX4X4:
1372
renderManager_.SetUniformM4x4(&loc, data);
1373
break;
1374
}
1375
}
1376
}
1377
1378
void OpenGLContext::Draw(int vertexCount, int offset) {
1379
_dbg_assert_msg_(curVBuffer_ != nullptr, "Can't call Draw without a vertex buffer");
1380
ApplySamplers();
1381
_assert_(curPipeline_->inputLayout);
1382
renderManager_.Draw(curPipeline_->inputLayout->inputLayout_, curVBuffer_->buffer_, curVBufferOffset_, curPipeline_->prim, offset, vertexCount);
1383
}
1384
1385
void OpenGLContext::DrawIndexed(int vertexCount, int offset) {
1386
_dbg_assert_msg_(curVBuffer_ != nullptr, "Can't call DrawIndexed without a vertex buffer");
1387
_dbg_assert_msg_(curIBuffer_ != nullptr, "Can't call DrawIndexed without an index buffer");
1388
ApplySamplers();
1389
_assert_(curPipeline_->inputLayout);
1390
renderManager_.DrawIndexed(
1391
curPipeline_->inputLayout->inputLayout_,
1392
curVBuffer_->buffer_, curVBufferOffset_,
1393
curIBuffer_->buffer_, curIBufferOffset_ + offset * sizeof(uint32_t),
1394
curPipeline_->prim, vertexCount, GL_UNSIGNED_SHORT);
1395
}
1396
1397
void OpenGLContext::DrawUP(const void *vdata, int vertexCount) {
1398
_assert_(curPipeline_->inputLayout != nullptr);
1399
int stride = curPipeline_->inputLayout->stride;
1400
uint32_t dataSize = stride * vertexCount;
1401
1402
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
1403
1404
GLRBuffer *buf;
1405
uint32_t offset;
1406
uint8_t *dest = frameData.push->Allocate(dataSize, 4, &buf, &offset);
1407
memcpy(dest, vdata, dataSize);
1408
1409
ApplySamplers();
1410
_assert_(curPipeline_->inputLayout);
1411
renderManager_.Draw(curPipeline_->inputLayout->inputLayout_, buf, offset, curPipeline_->prim, 0, vertexCount);
1412
}
1413
1414
void OpenGLContext::DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) {
1415
_assert_(curPipeline_->inputLayout != nullptr);
1416
int stride = curPipeline_->inputLayout->stride;
1417
uint32_t vdataSize = stride * vertexCount;
1418
uint32_t idataSize = indexCount * sizeof(u16);
1419
1420
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
1421
1422
GLRBuffer *vbuf;
1423
uint32_t voffset;
1424
uint8_t *dest = frameData.push->Allocate(vdataSize, 4, &vbuf, &voffset);
1425
memcpy(dest, vdata, vdataSize);
1426
1427
GLRBuffer *ibuf;
1428
uint32_t ioffset;
1429
dest = frameData.push->Allocate(idataSize, 4, &ibuf, &ioffset);
1430
memcpy(dest, idata, idataSize);
1431
1432
ApplySamplers();
1433
renderManager_.DrawIndexed(curPipeline_->inputLayout->inputLayout_, vbuf, voffset, ibuf, ioffset, curPipeline_->prim, indexCount, GL_UNSIGNED_SHORT, 1);
1434
}
1435
1436
void OpenGLContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) {
1437
if (draws.is_empty() || !vertexCount || !indexCount) {
1438
return;
1439
}
1440
1441
BindPipeline(draws[0].pipeline);
1442
UpdateDynamicUniformBuffer(ub, ubSize);
1443
1444
_assert_(curPipeline_->inputLayout != nullptr);
1445
int stride = curPipeline_->inputLayout->stride;
1446
uint32_t vdataSize = stride * vertexCount;
1447
int indexSize = sizeof(u16);
1448
uint32_t idataSize = indexCount * indexSize;
1449
1450
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
1451
1452
GLRBuffer *vbuf;
1453
uint32_t voffset;
1454
uint8_t *dest = frameData.push->Allocate(vdataSize, 4, &vbuf, &voffset);
1455
memcpy(dest, vdata, vdataSize);
1456
1457
GLRBuffer *ibuf;
1458
uint32_t ioffset;
1459
dest = frameData.push->Allocate(idataSize, 4, &ibuf, &ioffset);
1460
memcpy(dest, idata, idataSize);
1461
1462
ApplySamplers();
1463
for (auto &draw : draws) {
1464
if (draw.pipeline != curPipeline_) {
1465
OpenGLPipeline *glPipeline = (OpenGLPipeline *)draw.pipeline;
1466
_dbg_assert_(glPipeline->inputLayout->stride == stride);
1467
BindPipeline(glPipeline); // this updated curPipeline_.
1468
UpdateDynamicUniformBuffer(ub, ubSize);
1469
}
1470
if (draw.bindTexture) {
1471
renderManager_.BindTexture(0, ((OpenGLTexture *)draw.bindTexture)->GetTex());
1472
} else if (draw.bindFramebufferAsTex) {
1473
renderManager_.BindFramebufferAsTexture(((OpenGLFramebuffer*)draw.bindFramebufferAsTex)->framebuffer_, 0, GL_COLOR_BUFFER_BIT);
1474
}
1475
GLRect2D scissor;
1476
scissor.x = draw.clipx;
1477
scissor.y = draw.clipy;
1478
scissor.w = draw.clipw;
1479
scissor.h = draw.cliph;
1480
renderManager_.SetScissor(scissor);
1481
renderManager_.DrawIndexed(curPipeline_->inputLayout->inputLayout_, vbuf, voffset, ibuf, ioffset + draw.indexOffset * indexSize, curPipeline_->prim, draw.indexCount, GL_UNSIGNED_SHORT, 1);
1482
}
1483
}
1484
1485
void OpenGLContext::Clear(Aspect aspects, uint32_t colorval, float depthVal, int stencilVal) {
1486
float col[4];
1487
Uint8x4ToFloat4(col, colorval);
1488
GLuint glMask = 0;
1489
if (aspects & Aspect::COLOR_BIT) {
1490
glMask |= GL_COLOR_BUFFER_BIT;
1491
}
1492
if (aspects & Aspect::DEPTH_BIT) {
1493
glMask |= GL_DEPTH_BUFFER_BIT;
1494
}
1495
if (aspects & Aspect::STENCIL_BIT) {
1496
glMask |= GL_STENCIL_BUFFER_BIT;
1497
}
1498
renderManager_.Clear(colorval, depthVal, stencilVal, glMask, 0xF, 0, 0, targetWidth_, targetHeight_);
1499
}
1500
1501
DrawContext *T3DCreateGLContext(bool canChangeSwapInterval) {
1502
return new OpenGLContext(canChangeSwapInterval);
1503
}
1504
1505
OpenGLInputLayout::~OpenGLInputLayout() {
1506
render_->DeleteInputLayout(inputLayout_);
1507
}
1508
1509
void OpenGLInputLayout::Compile(const InputLayoutDesc &desc) {
1510
// TODO: This is only accurate if there's only one stream. But whatever, for now we
1511
// never use multiple streams anyway.
1512
stride = desc.stride;
1513
1514
std::vector<GLRInputLayout::Entry> entries;
1515
for (auto &attr : desc.attributes) {
1516
GLRInputLayout::Entry entry;
1517
entry.location = attr.location;
1518
entry.offset = attr.offset;
1519
switch (attr.format) {
1520
case DataFormat::R32G32_FLOAT:
1521
entry.count = 2;
1522
entry.type = GL_FLOAT;
1523
entry.normalized = GL_FALSE;
1524
break;
1525
case DataFormat::R32G32B32_FLOAT:
1526
entry.count = 3;
1527
entry.type = GL_FLOAT;
1528
entry.normalized = GL_FALSE;
1529
break;
1530
case DataFormat::R32G32B32A32_FLOAT:
1531
entry.count = 4;
1532
entry.type = GL_FLOAT;
1533
entry.normalized = GL_FALSE;
1534
break;
1535
case DataFormat::R8G8B8A8_UNORM:
1536
entry.count = 4;
1537
entry.type = GL_UNSIGNED_BYTE;
1538
entry.normalized = GL_TRUE;
1539
break;
1540
case DataFormat::UNDEFINED:
1541
default:
1542
ERROR_LOG(Log::G3D, "Thin3DGLVertexFormat: Invalid or unknown component type applied.");
1543
break;
1544
}
1545
1546
entries.push_back(entry);
1547
}
1548
if (!entries.empty()) {
1549
inputLayout_ = render_->CreateInputLayout(entries, stride);
1550
} else {
1551
inputLayout_ = nullptr;
1552
}
1553
}
1554
1555
Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) {
1556
CheckGLExtensions();
1557
1558
// TODO: Support multiview later. (It's our only use case for multi layers).
1559
_dbg_assert_(desc.numLayers == 1);
1560
1561
GLRFramebuffer *framebuffer = renderManager_.CreateFramebuffer(desc.width, desc.height, desc.z_stencil, desc.tag);
1562
OpenGLFramebuffer *fbo = new OpenGLFramebuffer(&renderManager_, framebuffer);
1563
return fbo;
1564
}
1565
1566
void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
1567
OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo;
1568
GLRRenderPassAction color = (GLRRenderPassAction)rp.color;
1569
GLRRenderPassAction depth = (GLRRenderPassAction)rp.depth;
1570
GLRRenderPassAction stencil = (GLRRenderPassAction)rp.stencil;
1571
1572
renderManager_.BindFramebufferAsRenderTarget(fb ? fb->framebuffer_ : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, tag);
1573
curRenderTarget_ = fb;
1574
}
1575
1576
void OpenGLContext::CopyFramebufferImage(Framebuffer *fbsrc, int srcLevel, int srcX, int srcY, int srcZ, Framebuffer *fbdst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) {
1577
OpenGLFramebuffer *src = (OpenGLFramebuffer *)fbsrc;
1578
OpenGLFramebuffer *dst = (OpenGLFramebuffer *)fbdst;
1579
1580
int glAspect = 0;
1581
if (aspects & Aspect::COLOR_BIT) {
1582
glAspect |= GL_COLOR_BUFFER_BIT;
1583
} else if (aspects & (Aspect::STENCIL_BIT | Aspect::DEPTH_BIT)) {
1584
if (aspects & Aspect::DEPTH_BIT)
1585
glAspect |= GL_DEPTH_BUFFER_BIT;
1586
if (aspects & Aspect::STENCIL_BIT)
1587
glAspect |= GL_STENCIL_BUFFER_BIT;
1588
}
1589
renderManager_.CopyFramebuffer(src->framebuffer_, GLRect2D{ srcX, srcY, width, height }, dst->framebuffer_, GLOffset2D{ dstX, dstY }, glAspect, tag);
1590
}
1591
1592
bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *fbdst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter linearFilter, const char *tag) {
1593
OpenGLFramebuffer *src = (OpenGLFramebuffer *)fbsrc;
1594
OpenGLFramebuffer *dst = (OpenGLFramebuffer *)fbdst;
1595
GLuint aspect = 0;
1596
if (aspects & Aspect::COLOR_BIT)
1597
aspect |= GL_COLOR_BUFFER_BIT;
1598
if (aspects & Aspect::DEPTH_BIT)
1599
aspect |= GL_DEPTH_BUFFER_BIT;
1600
if (aspects & Aspect::STENCIL_BIT)
1601
aspect |= GL_STENCIL_BUFFER_BIT;
1602
1603
renderManager_.BlitFramebuffer(src->framebuffer_, GLRect2D{ srcX1, srcY1, srcX2 - srcX1, srcY2 - srcY1 }, dst->framebuffer_, GLRect2D{ dstX1, dstY1, dstX2 - dstX1, dstY2 - dstY1 }, aspect, linearFilter == FB_BLIT_LINEAR, tag);
1604
return true;
1605
}
1606
1607
void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, Aspect aspects, int layer) {
1608
OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo;
1609
_assert_(binding < MAX_TEXTURE_SLOTS);
1610
1611
GLuint glAspect = 0;
1612
if (aspects & Aspect::COLOR_BIT) {
1613
glAspect |= GL_COLOR_BUFFER_BIT;
1614
boundTextures_[binding] = &fb->framebuffer_->color_texture;
1615
}
1616
if (aspects & Aspect::DEPTH_BIT) {
1617
glAspect |= GL_DEPTH_BUFFER_BIT;
1618
boundTextures_[binding] = &fb->framebuffer_->z_stencil_texture;
1619
}
1620
if (aspects & Aspect::STENCIL_BIT) {
1621
glAspect |= GL_STENCIL_BUFFER_BIT;
1622
boundTextures_[binding] = &fb->framebuffer_->z_stencil_texture;
1623
}
1624
renderManager_.BindFramebufferAsTexture(fb->framebuffer_, binding, glAspect);
1625
}
1626
1627
void OpenGLContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {
1628
OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo;
1629
if (fb) {
1630
*w = fb->Width();
1631
*h = fb->Height();
1632
} else {
1633
*w = targetWidth_;
1634
*h = targetHeight_;
1635
}
1636
}
1637
1638
uint64_t OpenGLContext::GetNativeObject(NativeObject obj, void *srcObject) {
1639
switch (obj) {
1640
case NativeObject::RENDER_MANAGER:
1641
return (uint64_t)(uintptr_t)&renderManager_;
1642
case NativeObject::TEXTURE_VIEW: // Gets the GLRTexture *
1643
return (uint64_t)(((OpenGLTexture *)srcObject)->GetTex());
1644
default:
1645
return 0;
1646
}
1647
}
1648
1649
uint32_t OpenGLContext::GetDataFormatSupport(DataFormat fmt) const {
1650
switch (fmt) {
1651
case DataFormat::R4G4B4A4_UNORM_PACK16:
1652
case DataFormat::R5G6B5_UNORM_PACK16:
1653
case DataFormat::R5G5B5A1_UNORM_PACK16:
1654
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_AUTOGEN_MIPS; // native support
1655
1656
case DataFormat::R8G8B8A8_UNORM:
1657
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT | FMT_AUTOGEN_MIPS;
1658
1659
case DataFormat::A1R5G5B5_UNORM_PACK16:
1660
return FMT_TEXTURE; // we will emulate this! Very fast to convert from R5G5B5A1_UNORM_PACK16 during upload.
1661
1662
case DataFormat::R32_FLOAT:
1663
case DataFormat::R32G32_FLOAT:
1664
case DataFormat::R32G32B32_FLOAT:
1665
case DataFormat::R32G32B32A32_FLOAT:
1666
return FMT_INPUTLAYOUT;
1667
1668
case DataFormat::R8_UNORM:
1669
return FMT_TEXTURE;
1670
case DataFormat::R16_UNORM:
1671
if (!gl_extensions.IsGLES) {
1672
return FMT_TEXTURE;
1673
} else {
1674
return 0;
1675
}
1676
break;
1677
1678
case DataFormat::BC1_RGBA_UNORM_BLOCK:
1679
case DataFormat::BC2_UNORM_BLOCK:
1680
case DataFormat::BC3_UNORM_BLOCK:
1681
return gl_extensions.supportsBC123 ? FMT_TEXTURE : 0;
1682
1683
case DataFormat::BC4_UNORM_BLOCK:
1684
case DataFormat::BC5_UNORM_BLOCK:
1685
return gl_extensions.supportsBC45 ? FMT_TEXTURE : 0;
1686
1687
case DataFormat::BC7_UNORM_BLOCK:
1688
return gl_extensions.supportsBC7 ? FMT_TEXTURE : 0;
1689
1690
case DataFormat::ASTC_4x4_UNORM_BLOCK:
1691
return gl_extensions.supportsASTC ? FMT_TEXTURE : 0;
1692
1693
case DataFormat::ETC2_R8G8B8_UNORM_BLOCK:
1694
case DataFormat::ETC2_R8G8B8A1_UNORM_BLOCK:
1695
case DataFormat::ETC2_R8G8B8A8_UNORM_BLOCK:
1696
return gl_extensions.supportsETC2 ? FMT_TEXTURE : 0;
1697
1698
default:
1699
return 0;
1700
}
1701
}
1702
1703
} // namespace Draw
1704
1705