CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

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

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