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