Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qrhigles2.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qrhigles2_p.h"
5#include <QOffscreenSurface>
6#include <QOpenGLContext>
7#include <QtCore/qmap.h>
8#include <QtGui/private/qopenglextensions_p.h>
9#include <QtGui/private/qopenglprogrambinarycache_p.h>
10#include <qpa/qplatformopenglcontext.h>
11#include <qmath.h>
12
14
15/*
16 OpenGL backend. Binding vertex attribute locations and decomposing uniform
17 buffers into uniforms are handled transparently to the application via the
18 reflection data (QShaderDescription). Real uniform buffers are never used,
19 regardless of the GLSL version. Textures and buffers feature no special
20 logic, it's all just glTexSubImage2D and glBufferSubData (with "dynamic"
21 buffers set to GL_DYNAMIC_DRAW). The swapchain and the associated
22 renderbuffer for depth-stencil will be dummies since we have no control over
23 the underlying buffers here. While the baseline here is plain GLES 2.0, some
24 modern GL(ES) features like multisample renderbuffers, blits, and compute are
25 used when available. Also functional with core profile contexts.
26*/
27
154#ifndef GL_BGRA
155#define GL_BGRA 0x80E1
156#endif
157
158#ifndef GL_R8
159#define GL_R8 0x8229
160#endif
161
162#ifndef GL_RG8
163#define GL_RG8 0x822B
164#endif
165
166#ifndef GL_RG
167#define GL_RG 0x8227
168#endif
169
170#ifndef GL_R16
171#define GL_R16 0x822A
172#endif
173
174#ifndef GL_RG16
175#define GL_RG16 0x822C
176#endif
177
178#ifndef GL_RED
179#define GL_RED 0x1903
180#endif
181
182#ifndef GL_RGBA8
183#define GL_RGBA8 0x8058
184#endif
185
186#ifndef GL_RGBA32F
187#define GL_RGBA32F 0x8814
188#endif
189
190#ifndef GL_RGBA16F
191#define GL_RGBA16F 0x881A
192#endif
193
194#ifndef GL_R16F
195#define GL_R16F 0x822D
196#endif
197
198#ifndef GL_R32F
199#define GL_R32F 0x822E
200#endif
201
202#ifndef GL_HALF_FLOAT
203#define GL_HALF_FLOAT 0x140B
204#endif
205
206#ifndef GL_DEPTH_COMPONENT16
207#define GL_DEPTH_COMPONENT16 0x81A5
208#endif
209
210#ifndef GL_DEPTH_COMPONENT24
211#define GL_DEPTH_COMPONENT24 0x81A6
212#endif
213
214#ifndef GL_DEPTH_COMPONENT32F
215#define GL_DEPTH_COMPONENT32F 0x8CAC
216#endif
217
218#ifndef GL_UNSIGNED_INT_24_8
219#define GL_UNSIGNED_INT_24_8 0x84FA
220#endif
221
222#ifndef GL_STENCIL_INDEX
223#define GL_STENCIL_INDEX 0x1901
224#endif
225
226#ifndef GL_STENCIL_INDEX8
227#define GL_STENCIL_INDEX8 0x8D48
228#endif
229
230#ifndef GL_DEPTH24_STENCIL8
231#define GL_DEPTH24_STENCIL8 0x88F0
232#endif
233
234#ifndef GL_DEPTH_STENCIL_ATTACHMENT
235#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
236#endif
237
238#ifndef GL_DEPTH_STENCIL
239#define GL_DEPTH_STENCIL 0x84F9
240#endif
241
242#ifndef GL_PRIMITIVE_RESTART_FIXED_INDEX
243#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
244#endif
245
246#ifndef GL_FRAMEBUFFER_SRGB
247#define GL_FRAMEBUFFER_SRGB 0x8DB9
248#endif
249
250#ifndef GL_READ_FRAMEBUFFER
251#define GL_READ_FRAMEBUFFER 0x8CA8
252#endif
253
254#ifndef GL_DRAW_FRAMEBUFFER
255#define GL_DRAW_FRAMEBUFFER 0x8CA9
256#endif
257
258#ifndef GL_MAX_DRAW_BUFFERS
259#define GL_MAX_DRAW_BUFFERS 0x8824
260#endif
261
262#ifndef GL_TEXTURE_COMPARE_MODE
263#define GL_TEXTURE_COMPARE_MODE 0x884C
264#endif
265
266#ifndef GL_COMPARE_REF_TO_TEXTURE
267#define GL_COMPARE_REF_TO_TEXTURE 0x884E
268#endif
269
270#ifndef GL_TEXTURE_COMPARE_FUNC
271#define GL_TEXTURE_COMPARE_FUNC 0x884D
272#endif
273
274#ifndef GL_MAX_SAMPLES
275#define GL_MAX_SAMPLES 0x8D57
276#endif
277
278#ifndef GL_SHADER_STORAGE_BUFFER
279#define GL_SHADER_STORAGE_BUFFER 0x90D2
280#endif
281
282#ifndef GL_READ_ONLY
283#define GL_READ_ONLY 0x88B8
284#endif
285
286#ifndef GL_WRITE_ONLY
287#define GL_WRITE_ONLY 0x88B9
288#endif
289
290#ifndef GL_READ_WRITE
291#define GL_READ_WRITE 0x88BA
292#endif
293
294#ifndef GL_COMPUTE_SHADER
295#define GL_COMPUTE_SHADER 0x91B9
296#endif
297
298#ifndef GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT
299#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
300#endif
301
302#ifndef GL_ELEMENT_ARRAY_BARRIER_BIT
303#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
304#endif
305
306#ifndef GL_UNIFORM_BARRIER_BIT
307#define GL_UNIFORM_BARRIER_BIT 0x00000004
308#endif
309
310#ifndef GL_BUFFER_UPDATE_BARRIER_BIT
311#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
312#endif
313
314#ifndef GL_SHADER_STORAGE_BARRIER_BIT
315#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
316#endif
317
318#ifndef GL_TEXTURE_FETCH_BARRIER_BIT
319#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
320#endif
321
322#ifndef GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
323#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
324#endif
325
326#ifndef GL_PIXEL_BUFFER_BARRIER_BIT
327#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
328#endif
329
330#ifndef GL_TEXTURE_UPDATE_BARRIER_BIT
331#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
332#endif
333
334#ifndef GL_FRAMEBUFFER_BARRIER_BIT
335#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
336#endif
337
338#ifndef GL_ALL_BARRIER_BITS
339#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
340#endif
341
342#ifndef GL_VERTEX_PROGRAM_POINT_SIZE
343#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
344#endif
345
346#ifndef GL_POINT_SPRITE
347#define GL_POINT_SPRITE 0x8861
348#endif
349
350#ifndef GL_MAP_READ_BIT
351#define GL_MAP_READ_BIT 0x0001
352#endif
353
354#ifndef GL_MAP_WRITE_BIT
355#define GL_MAP_WRITE_BIT 0x0002
356#endif
357
358#ifndef GL_TEXTURE_2D_MULTISAMPLE
359#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
360#endif
361
362#ifndef GL_TEXTURE_2D_MULTISAMPLE_ARRAY
363#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
364#endif
365
366#ifndef GL_TEXTURE_EXTERNAL_OES
367#define GL_TEXTURE_EXTERNAL_OES 0x8D65
368#endif
369
370#ifndef GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS
371#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
372#endif
373
374#ifndef GL_MAX_COMPUTE_WORK_GROUP_COUNT
375#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE
376#endif
377
378#ifndef GL_MAX_COMPUTE_WORK_GROUP_SIZE
379#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF
380#endif
381
382#ifndef GL_TEXTURE_CUBE_MAP_SEAMLESS
383#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
384#endif
385
386#ifndef GL_CONTEXT_LOST
387#define GL_CONTEXT_LOST 0x0507
388#endif
389
390#ifndef GL_PROGRAM_BINARY_LENGTH
391#define GL_PROGRAM_BINARY_LENGTH 0x8741
392#endif
393
394#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
395#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
396#endif
397
398#ifndef GL_UNPACK_ROW_LENGTH
399#define GL_UNPACK_ROW_LENGTH 0x0CF2
400#endif
401
402#ifndef GL_TEXTURE_3D
403#define GL_TEXTURE_3D 0x806F
404#endif
405
406#ifndef GL_TEXTURE_WRAP_R
407#define GL_TEXTURE_WRAP_R 0x8072
408#endif
409
410#ifndef GL_TEXTURE_RECTANGLE
411#define GL_TEXTURE_RECTANGLE 0x84F5
412#endif
413
414#ifndef GL_TEXTURE_2D_ARRAY
415#define GL_TEXTURE_2D_ARRAY 0x8C1A
416#endif
417
418#ifndef GL_MAX_ARRAY_TEXTURE_LAYERS
419#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
420#endif
421
422#ifndef GL_MAX_VERTEX_UNIFORM_COMPONENTS
423#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
424#endif
425
426#ifndef GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
427#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
428#endif
429
430#ifndef GL_MAX_VERTEX_UNIFORM_VECTORS
431#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
432#endif
433
434#ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS
435#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
436#endif
437
438#ifndef GL_RGB10_A2
439#define GL_RGB10_A2 0x8059
440#endif
441
442#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
443#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
444#endif
445
446#ifndef GL_MAX_VARYING_COMPONENTS
447#define GL_MAX_VARYING_COMPONENTS 0x8B4B
448#endif
449
450#ifndef GL_MAX_VARYING_FLOATS
451#define GL_MAX_VARYING_FLOATS 0x8B4B
452#endif
453
454#ifndef GL_MAX_VARYING_VECTORS
455#define GL_MAX_VARYING_VECTORS 0x8DFC
456#endif
457
458#ifndef GL_TESS_CONTROL_SHADER
459#define GL_TESS_CONTROL_SHADER 0x8E88
460#endif
461
462#ifndef GL_TESS_EVALUATION_SHADER
463#define GL_TESS_EVALUATION_SHADER 0x8E87
464#endif
465
466#ifndef GL_PATCH_VERTICES
467#define GL_PATCH_VERTICES 0x8E72
468#endif
469
470#ifndef GL_LINE
471#define GL_LINE 0x1B01
472#endif
473
474#ifndef GL_FILL
475#define GL_FILL 0x1B02
476#endif
477
478#ifndef GL_PATCHES
479#define GL_PATCHES 0x000E
480#endif
481
482#ifndef GL_GEOMETRY_SHADER
483#define GL_GEOMETRY_SHADER 0x8DD9
484#endif
485
486#ifndef GL_BACK_LEFT
487#define GL_BACK_LEFT 0x0402
488#endif
489
490#ifndef GL_BACK_RIGHT
491#define GL_BACK_RIGHT 0x0403
492#endif
493
494#ifndef GL_TEXTURE_1D
495# define GL_TEXTURE_1D 0x0DE0
496#endif
497
498#ifndef GL_TEXTURE_1D_ARRAY
499# define GL_TEXTURE_1D_ARRAY 0x8C18
500#endif
501
502#ifndef GL_HALF_FLOAT
503#define GL_HALF_FLOAT 0x140B
504#endif
505
506#ifndef GL_MAX_VERTEX_OUTPUT_COMPONENTS
507#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
508#endif
509
515QRhiGles2InitParams::QRhiGles2InitParams()
516{
518}
519
536QOffscreenSurface *QRhiGles2InitParams::newFallbackSurface(const QSurfaceFormat &format)
537{
539
540 // To resolve all fields in the format as much as possible, create a context.
541 // This may be heavy, but allows avoiding BAD_MATCH on some systems.
542 QOpenGLContext tempContext;
543 tempContext.setFormat(fmt);
544 if (tempContext.create())
545 fmt = tempContext.format();
546 else
547 qWarning("QRhiGles2: Failed to create temporary context");
548
550 s->setFormat(fmt);
551 s->create();
552
553 return s;
554}
555
557 : ofr(this)
558{
559 requestedFormat = params->format;
560 fallbackSurface = params->fallbackSurface;
561 maybeWindow = params->window; // may be null
562 maybeShareContext = params->shareContext; // may be null
563
564 importedContext = importDevice != nullptr;
565 if (importedContext) {
566 ctx = importDevice->context;
567 if (!ctx) {
568 qWarning("No OpenGL context given, cannot import");
569 importedContext = false;
570 }
571 }
572}
573
575{
577 return nullptr;
578
579 QSurface *currentSurface = ctx->surface();
580 if (!currentSurface)
581 return nullptr;
582
583 if (currentSurface->surfaceClass() == QSurface::Window && !currentSurface->surfaceHandle())
584 return nullptr;
585
586 return currentSurface;
587}
588
590{
591 // With Apple's deprecated OpenGL support we need to minimize the usage of
592 // QOffscreenSurface since delicate problems can pop up with
593 // NSOpenGLContext and drawables.
594#if defined(Q_OS_MACOS)
595 return maybeWindow && maybeWindow->handle() ? static_cast<QSurface *>(maybeWindow) : fallbackSurface;
596#else
597 return fallbackSurface;
598#endif
599}
600
602{
603 if (!surface) {
604 // null means any surface is good because not going to render
606 return true;
607 // if the context is not already current with a valid surface, use our
608 // fallback surface, but platform specific quirks may apply
609 surface = evaluateFallbackSurface();
610 } else if (surface->surfaceClass() == QSurface::Window && !surface->surfaceHandle()) {
611 // the window is not usable anymore (no native window underneath), behave as if offscreen
612 surface = evaluateFallbackSurface();
614 // bail out if the makeCurrent is not necessary
615 return true;
616 }
618
619 if (!ctx->makeCurrent(surface)) {
620 if (ctx->isValid()) {
621 qWarning("QRhiGles2: Failed to make context current. Expect bad things to happen.");
622 } else {
623 qWarning("QRhiGles2: Context is lost.");
624 contextLost = true;
625 }
626 return false;
627 }
628
629 return true;
630}
631
633{
634 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
635 switch (format) {
636 case QRhiTexture::BC1:
637 return srgb ? 0x8C4C : 0x83F0;
638 case QRhiTexture::BC2:
639 return srgb ? 0x8C4E : 0x83F2;
640 case QRhiTexture::BC3:
641 return srgb ? 0x8C4F : 0x83F3;
642
644 return srgb ? 0x9275 : 0x9274;
646 return srgb ? 0x9277 : 0x9276;
648 return srgb ? 0x9279 : 0x9278;
649
651 return srgb ? 0x93D0 : 0x93B0;
653 return srgb ? 0x93D1 : 0x93B1;
655 return srgb ? 0x93D2 : 0x93B2;
657 return srgb ? 0x93D3 : 0x93B3;
659 return srgb ? 0x93D4 : 0x93B4;
661 return srgb ? 0x93D5 : 0x93B5;
663 return srgb ? 0x93D6 : 0x93B6;
665 return srgb ? 0x93D7 : 0x93B7;
667 return srgb ? 0x93D8 : 0x93B8;
669 return srgb ? 0x93D9 : 0x93B9;
671 return srgb ? 0x93DA : 0x93BA;
673 return srgb ? 0x93DB : 0x93BB;
675 return srgb ? 0x93DC : 0x93BC;
677 return srgb ? 0x93DD : 0x93BD;
678
679 default:
680 return 0; // this is reachable, just return an invalid format
681 }
682}
683
684bool QRhiGles2::create(QRhi::Flags flags)
685{
687 rhiFlags = flags;
688
689 if (!importedContext) {
690 ctx = new QOpenGLContext;
692 if (maybeShareContext) {
693 ctx->setShareContext(maybeShareContext);
694 ctx->setScreen(maybeShareContext->screen());
695 } else if (QOpenGLContext *shareContext = qt_gl_global_share_context()) {
696 ctx->setShareContext(shareContext);
697 ctx->setScreen(shareContext->screen());
698 } else if (maybeWindow) {
699 ctx->setScreen(maybeWindow->screen());
700 }
701 if (!ctx->create()) {
702 qWarning("QRhiGles2: Failed to create context");
703 delete ctx;
704 ctx = nullptr;
705 return false;
706 }
707 qCDebug(QRHI_LOG_INFO) << "Created OpenGL context" << ctx->format();
708 }
709
710 if (!ensureContext(maybeWindow ? maybeWindow : fallbackSurface)) // see 'window' discussion in QRhiGles2InitParams comments
711 return false;
712
713 f = static_cast<QOpenGLExtensions *>(ctx->extraFunctions());
714 const QSurfaceFormat actualFormat = ctx->format();
716
717 if (!caps.gles) {
718 glPolygonMode = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum)>(
719 ctx->getProcAddress(QByteArrayLiteral("glPolygonMode")));
720
721 glTexImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(
722 GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, const void *)>(
723 ctx->getProcAddress(QByteArrayLiteral("glTexImage1D")));
724
725 glTexStorage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei)>(
726 ctx->getProcAddress(QByteArrayLiteral("glTexStorage1D")));
727
728 glTexSubImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(
729 GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *)>(
730 ctx->getProcAddress(QByteArrayLiteral("glTexSubImage1D")));
731
732 glCopyTexSubImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint,
733 GLint, GLsizei)>(
734 ctx->getProcAddress(QByteArrayLiteral("glCopyTexSubImage1D")));
735
736 glCompressedTexImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(
737 GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *)>(
738 ctx->getProcAddress(QByteArrayLiteral("glCompressedTexImage1D")));
739
740 glCompressedTexSubImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(
741 GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *)>(
742 ctx->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage1D")));
743
744 glFramebufferTexture1D =
745 reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum, GLenum, GLuint, GLint)>(
746 ctx->getProcAddress(QByteArrayLiteral("glFramebufferTexture1D")));
747 }
748
749 const char *vendor = reinterpret_cast<const char *>(f->glGetString(GL_VENDOR));
750 const char *renderer = reinterpret_cast<const char *>(f->glGetString(GL_RENDERER));
751 const char *version = reinterpret_cast<const char *>(f->glGetString(GL_VERSION));
752 if (vendor && renderer && version)
753 qCDebug(QRHI_LOG_INFO, "OpenGL VENDOR: %s RENDERER: %s VERSION: %s", vendor, renderer, version);
754
755 if (vendor) {
758 }
759 if (renderer) {
762 }
763 if (version)
765
766 caps.ctxMajor = actualFormat.majorVersion();
767 caps.ctxMinor = actualFormat.minorVersion();
768
769 GLint n = 0;
770 f->glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &n);
771 if (n > 0) {
772 QVarLengthArray<GLint, 16> compressedTextureFormats(n);
773 f->glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, compressedTextureFormats.data());
774 for (GLint format : compressedTextureFormats)
776
777 }
778 // The above looks nice, if only it worked always. With GLES the list we
779 // query is likely the full list of compressed formats (mostly anything
780 // that can be decoded). With OpenGL however the list is not required to
781 // include all formats due to the way the spec is worded. For instance, we
782 // cannot rely on ASTC formats being present in the list on non-ES. Some
783 // drivers do include them (Intel, NVIDIA), some don't (Mesa). On the other
784 // hand, relying on extension strings only is not ok: for example, Intel
785 // reports GL_KHR_texture_compression_astc_ldr whereas NVIDIA doesn't. So
786 // the only reasonable thing to do is to query the list always and then see
787 // if there is something we can add - if not already in there.
788 std::array<QRhiTexture::Flags, 2> textureVariantFlags;
789 textureVariantFlags[0] = {};
790 textureVariantFlags[1] = QRhiTexture::sRGB;
791 if (f->hasOpenGLExtension(QOpenGLExtensions::DDSTextureCompression)) {
792 for (QRhiTexture::Flags f : textureVariantFlags) {
796 }
797 }
798 if (f->hasOpenGLExtension(QOpenGLExtensions::ETC2TextureCompression)) {
799 for (QRhiTexture::Flags f : textureVariantFlags) {
803 }
804 }
805 if (f->hasOpenGLExtension(QOpenGLExtensions::ASTCTextureCompression)) {
806 for (QRhiTexture::Flags f : textureVariantFlags) {
820 }
821 }
822
823 f->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps.maxTextureSize);
824
825 if (!caps.gles || caps.ctxMajor >= 3) {
826 // non-ES or ES 3.0+
827 f->glGetIntegerv(GL_MAX_DRAW_BUFFERS, &caps.maxDrawBuffers);
829 f->glGetIntegerv(GL_MAX_SAMPLES, &caps.maxSamples);
831 } else {
832 // ES 2.0 / WebGL 1
834 caps.hasDrawBuffersFunc = false;
835 // This does not mean MSAA is not supported, just that we cannot query
836 // the supported sample counts.
837 caps.maxSamples = 1;
838 }
839
841 && f->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
842
844 && f->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
845
846 if (caps.gles)
848 else
849 caps.fixedIndexPrimitiveRestart = caps.ctxMajor > 4 || (caps.ctxMajor == 4 && caps.ctxMinor >= 3); // 4.3
850
852#ifdef Q_OS_WASM
853 // WebGL 2 behaves as if GL_PRIMITIVE_RESTART_FIXED_INDEX was always
854 // enabled (i.e. matching D3D/Metal), and the value cannot be passed to
855 // glEnable, so skip the call.
856#else
858#endif
859 }
860
864 caps.r16Format = f->hasOpenGLExtension(QOpenGLExtensions::Sized16Formats);
865 caps.floatFormats = caps.ctxMajor >= 3; // 3.0 or ES 3.0
866 caps.rgb10Formats = caps.ctxMajor >= 3; // 3.0 or ES 3.0
867 caps.depthTexture = caps.ctxMajor >= 3; // 3.0 or ES 3.0
869#ifdef Q_OS_WASM
871#else
873#endif
876
877 if (caps.gles)
878 caps.uniformBuffers = caps.ctxMajor >= 3; // ES 3.0
879 else
880 caps.uniformBuffers = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 1); // 3.1
881
883 caps.depth24 = f->hasOpenGLExtension(QOpenGLExtensions::Depth24);
884 caps.rgba8Format = f->hasOpenGLExtension(QOpenGLExtensions::Sized8Formats);
885
886 if (caps.gles)
887 caps.instancing = caps.ctxMajor >= 3; // ES 3.0
888 else
889 caps.instancing = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 3); // 3.3
890
891 caps.baseVertex = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // 3.2 or ES 3.2
892
893 if (caps.gles)
894 caps.compute = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 1); // ES 3.1
895 else
896 caps.compute = caps.ctxMajor > 4 || (caps.ctxMajor == 4 && caps.ctxMinor >= 3); // 4.3
897
898 if (caps.compute) {
900 GLint tgPerDim[3];
901 f->glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &tgPerDim[0]);
902 f->glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &tgPerDim[1]);
903 f->glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &tgPerDim[2]);
904 caps.maxThreadGroupsPerDimension = qMin(tgPerDim[0], qMin(tgPerDim[1], tgPerDim[2]));
908 }
909
910 if (caps.gles)
911 caps.textureCompareMode = caps.ctxMajor >= 3; // ES 3.0
912 else
914
915 // proper as in ES 3.0 (glMapBufferRange), not the old glMapBuffer
916 // extension(s) (which is not in ES 3.0...messy)
918
919 if (caps.gles)
921 else
923
924 caps.texelFetch = caps.ctxMajor >= 3; // 3.0 or ES 3.0
925 caps.intAttributes = caps.ctxMajor >= 3; // 3.0 or ES 3.0
927
928 if (caps.gles)
929 caps.multisampledTexture = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 1); // ES 3.1
930 else
932
933 // Program binary support: only the core stuff, do not bother with the old
934 // extensions like GL_OES_get_program_binary
935 if (caps.gles)
936 caps.programBinary = caps.ctxMajor >= 3; // ES 3.0
937 else
938 caps.programBinary = caps.ctxMajor > 4 || (caps.ctxMajor == 4 && caps.ctxMinor >= 1); // 4.1
939
940 if (caps.programBinary) {
941 GLint fmtCount = 0;
942 f->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
943 if (fmtCount < 1)
944 caps.programBinary = false;
945 }
946
947 caps.texture3D = caps.ctxMajor >= 3; // 3.0
948
949 if (caps.gles)
950 caps.texture1D = false; // ES
951 else
952 caps.texture1D = glTexImage1D && (caps.ctxMajor >= 2); // 2.0
953
954 if (caps.gles)
955 caps.tessellation = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // ES 3.2
956 else
957 caps.tessellation = caps.ctxMajor >= 4; // 4.0
958
959 if (caps.gles)
960 caps.geometryShader = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // ES 3.2
961 else
962 caps.geometryShader = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // 3.2
963
964 if (caps.ctxMajor >= 3) { // 3.0 or ES 3.0
965 GLint maxArraySize = 0;
966 f->glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxArraySize);
967 caps.maxTextureArraySize = maxArraySize;
968 } else {
970 }
971
972 // The ES 2.0 spec only has MAX_xxxx_VECTORS. ES 3.0 and up has both
973 // *VECTORS and *COMPONENTS. OpenGL 2.0-4.0 only has MAX_xxxx_COMPONENTS.
974 // 4.1 and above has both. What a mess.
975 if (caps.gles) {
976 GLint maxVertexUniformVectors = 0;
977 f->glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxVertexUniformVectors);
978 GLint maxFragmentUniformVectors = 0;
979 f->glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxFragmentUniformVectors);
980 caps.maxUniformVectors = qMin(maxVertexUniformVectors, maxFragmentUniformVectors);
981 } else {
982 GLint maxVertexUniformComponents = 0;
983 f->glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &maxVertexUniformComponents);
984 GLint maxFragmentUniformComponents = 0;
985 f->glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &maxFragmentUniformComponents);
986 caps.maxUniformVectors = qMin(maxVertexUniformComponents, maxFragmentUniformComponents) / 4;
987 }
988
990
991 if (caps.gles) {
993 } else if (caps.ctxMajor >= 3) {
994 GLint components = 0;
997 } else {
998 // OpenGL before 3.0 only has this, and not the same as
999 // MAX_VARYING_COMPONENTS strictly speaking, but will do.
1000 GLint components = 0;
1001 f->glGetIntegerv(GL_MAX_VARYING_FLOATS, &components);
1002 if (components > 0)
1004 }
1005
1006 if (!caps.gles) {
1008 if (!caps.coreProfile)
1009 f->glEnable(GL_POINT_SPRITE);
1010 } // else (with gles) these are always on
1011
1012 // Match D3D and others when it comes to seamless cubemap filtering.
1013 // ES 3.0+ has this always enabled. (hopefully)
1014 // ES 2.0 and GL < 3.2 will not have it.
1015 if (!caps.gles && (caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2)))
1017
1019
1020 // We always require GL_OVR_multiview2 for symmetry with other backends.
1021 caps.multiView = f->hasOpenGLExtension(QOpenGLExtensions::MultiView)
1022 && f->hasOpenGLExtension(QOpenGLExtensions::MultiViewExtended);
1023 if (caps.multiView) {
1024 glFramebufferTextureMultiviewOVR =
1025 reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei)>(
1026 ctx->getProcAddress(QByteArrayLiteral("glFramebufferTextureMultiviewOVR")));
1027 }
1028
1029 nativeHandlesStruct.context = ctx;
1030
1031 contextLost = false;
1032
1033 return true;
1034}
1035
1037{
1038 if (!f)
1039 return;
1040
1041 ensureContext();
1043
1044 if (vao) {
1045 f->glDeleteVertexArrays(1, &vao);
1046 vao = 0;
1047 }
1048
1049 for (uint shader : m_shaderCache)
1050 f->glDeleteShader(shader);
1052
1053 if (!importedContext) {
1054 delete ctx;
1055 ctx = nullptr;
1056 }
1057
1058 f = nullptr;
1059}
1060
1062{
1063 for (int i = releaseQueue.size() - 1; i >= 0; --i) {
1065 switch (e.type) {
1067 f->glDeleteBuffers(1, &e.buffer.buffer);
1068 break;
1070 f->glDeleteProgram(e.pipeline.program);
1071 break;
1073 f->glDeleteTextures(1, &e.texture.texture);
1074 break;
1076 f->glDeleteRenderbuffers(1, &e.renderbuffer.renderbuffer);
1077 f->glDeleteRenderbuffers(1, &e.renderbuffer.renderbuffer2);
1078 break;
1080 f->glDeleteFramebuffers(1, &e.textureRenderTarget.framebuffer);
1081 break;
1082 default:
1083 Q_UNREACHABLE();
1084 break;
1085 }
1086 releaseQueue.removeAt(i);
1087 }
1088}
1089
1091{
1093 // 1, 2, 4, 8, ...
1094 for (int i = 1; i <= caps.maxSamples; i *= 2)
1096 }
1098}
1099
1100int QRhiGles2::effectiveSampleCount(int sampleCount) const
1101{
1102 // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
1103 const int s = qBound(1, sampleCount, 64);
1105 qWarning("Attempted to set unsupported sample count %d", sampleCount);
1106 return 1;
1107 }
1108 return s;
1109}
1110
1112{
1113 return new QGles2SwapChain(this);
1114}
1115
1117{
1118 return new QGles2Buffer(this, type, usage, size);
1119}
1120
1122{
1123 // No real uniform buffers are used so no need to pretend there is any
1124 // alignment requirement.
1125 return 1;
1126}
1127
1129{
1130 return true;
1131}
1132
1134{
1135 return true;
1136}
1137
1139{
1140 return false;
1141}
1142
1144{
1145 return QMatrix4x4(); // identity
1146}
1147
1149 GLenum *glintformat, GLenum *glsizedintformat,
1150 GLenum *glformat, GLenum *gltype)
1151{
1152 switch (format) {
1153 case QRhiTexture::RGBA8:
1154 *glintformat = GL_RGBA;
1155 *glsizedintformat = caps.rgba8Format ? GL_RGBA8 : GL_RGBA;
1156 *glformat = GL_RGBA;
1157 *gltype = GL_UNSIGNED_BYTE;
1158 break;
1159 case QRhiTexture::BGRA8:
1160 *glintformat = caps.bgraInternalFormat ? GL_BGRA : GL_RGBA;
1161 *glsizedintformat = caps.rgba8Format ? GL_RGBA8 : GL_RGBA;
1162 *glformat = GL_BGRA;
1163 *gltype = GL_UNSIGNED_BYTE;
1164 break;
1165 case QRhiTexture::R16:
1166 *glintformat = GL_R16;
1167 *glsizedintformat = *glintformat;
1168 *glformat = GL_RED;
1169 *gltype = GL_UNSIGNED_SHORT;
1170 break;
1171 case QRhiTexture::RG16:
1172 *glintformat = GL_RG16;
1173 *glsizedintformat = *glintformat;
1174 *glformat = GL_RG;
1175 *gltype = GL_UNSIGNED_SHORT;
1176 break;
1177 case QRhiTexture::R8:
1178 *glintformat = GL_R8;
1179 *glsizedintformat = *glintformat;
1180 *glformat = GL_RED;
1181 *gltype = GL_UNSIGNED_BYTE;
1182 break;
1183 case QRhiTexture::RG8:
1184 *glintformat = GL_RG8;
1185 *glsizedintformat = *glintformat;
1186 *glformat = GL_RG;
1187 *gltype = GL_UNSIGNED_BYTE;
1188 break;
1190 *glintformat = caps.coreProfile ? GL_R8 : GL_ALPHA;
1191 *glsizedintformat = *glintformat;
1192 *glformat = caps.coreProfile ? GL_RED : GL_ALPHA;
1193 *gltype = GL_UNSIGNED_BYTE;
1194 break;
1196 *glintformat = GL_RGBA16F;
1197 *glsizedintformat = *glintformat;
1198 *glformat = GL_RGBA;
1199 *gltype = GL_HALF_FLOAT;
1200 break;
1202 *glintformat = GL_RGBA32F;
1203 *glsizedintformat = *glintformat;
1204 *glformat = GL_RGBA;
1205 *gltype = GL_FLOAT;
1206 break;
1207 case QRhiTexture::R16F:
1208 *glintformat = GL_R16F;
1209 *glsizedintformat = *glintformat;
1210 *glformat = GL_RED;
1211 *gltype = GL_HALF_FLOAT;
1212 break;
1213 case QRhiTexture::R32F:
1214 *glintformat = GL_R32F;
1215 *glsizedintformat = *glintformat;
1216 *glformat = GL_RED;
1217 *gltype = GL_FLOAT;
1218 break;
1220 *glintformat = GL_RGB10_A2;
1221 *glsizedintformat = *glintformat;
1222 *glformat = GL_RGBA;
1224 break;
1225 case QRhiTexture::D16:
1226 *glintformat = GL_DEPTH_COMPONENT16;
1227 *glsizedintformat = *glintformat;
1228 *glformat = GL_DEPTH_COMPONENT;
1229 *gltype = GL_UNSIGNED_SHORT;
1230 break;
1231 case QRhiTexture::D24:
1232 *glintformat = GL_DEPTH_COMPONENT24;
1233 *glsizedintformat = *glintformat;
1234 *glformat = GL_DEPTH_COMPONENT;
1235 *gltype = GL_UNSIGNED_INT;
1236 break;
1237 case QRhiTexture::D24S8:
1238 *glintformat = GL_DEPTH24_STENCIL8;
1239 *glsizedintformat = *glintformat;
1240 *glformat = GL_DEPTH_STENCIL;
1241 *gltype = GL_UNSIGNED_INT_24_8;
1242 break;
1243 case QRhiTexture::D32F:
1244 *glintformat = GL_DEPTH_COMPONENT32F;
1245 *glsizedintformat = *glintformat;
1246 *glformat = GL_DEPTH_COMPONENT;
1247 *gltype = GL_FLOAT;
1248 break;
1249 default:
1250 Q_UNREACHABLE();
1251 *glintformat = GL_RGBA;
1252 *glsizedintformat = caps.rgba8Format ? GL_RGBA8 : GL_RGBA;
1253 *glformat = GL_RGBA;
1254 *gltype = GL_UNSIGNED_BYTE;
1255 break;
1256 }
1257}
1258
1260{
1263
1264 switch (format) {
1265 case QRhiTexture::D16:
1266 case QRhiTexture::D32F:
1267 return caps.depthTexture;
1268
1269 case QRhiTexture::D24:
1270 return caps.depth24;
1271
1272 case QRhiTexture::D24S8:
1274
1275 case QRhiTexture::BGRA8:
1276 return caps.bgraExternalFormat;
1277
1278 case QRhiTexture::R8:
1279 return caps.r8Format;
1280
1281 case QRhiTexture::RG8:
1282 return caps.r8Format;
1283
1284 case QRhiTexture::R16:
1285 return caps.r16Format;
1286
1287 case QRhiTexture::RG16:
1288 return caps.r16Format;
1289
1292 return caps.floatFormats;
1293
1294 case QRhiTexture::R16F:
1295 case QRhiTexture::R32F:
1296 return caps.floatFormats;
1297
1299 return caps.rgb10Formats;
1300
1301 default:
1302 break;
1303 }
1304
1305 return true;
1306}
1307
1309{
1310 switch (feature) {
1314 return caps.msaaRenderBuffer;
1315 case QRhi::DebugMarkers:
1316 return false;
1317 case QRhi::Timestamps:
1318 return false;
1319 case QRhi::Instancing:
1320 return caps.instancing;
1322 return false;
1326 return true;
1328 return true;
1330 return caps.npotTextureFull;
1332 return caps.coreProfile;
1334 return caps.elementIndexUint;
1335 case QRhi::Compute:
1336 return caps.compute;
1337 case QRhi::WideLines:
1338 return !caps.coreProfile;
1340 return true;
1341 case QRhi::BaseVertex:
1342 return caps.baseVertex;
1343 case QRhi::BaseInstance:
1344 return false; // not in ES 3.2, so won't bother
1346 return true;
1348 return !caps.gles || caps.properMapBuffer;
1351 case QRhi::TexelFetch:
1352 return caps.texelFetch;
1356 return caps.intAttributes;
1360 return false;
1362 return caps.programBinary;
1364 return !caps.gles || caps.ctxMajor >= 3;
1366 return true;
1368 return caps.texture3D;
1370 return caps.texture3D;
1372 return caps.maxTextureArraySize > 0;
1373 case QRhi::Tessellation:
1374 return caps.tessellation;
1376 return caps.geometryShader;
1378 return false;
1380 return !caps.gles;
1382 return caps.texture1D;
1384 return caps.texture1D;
1386 return caps.halfAttributes;
1388 return caps.texture1D;
1390 return caps.texture3D;
1391 case QRhi::MultiView:
1392 return caps.multiView && caps.maxTextureArraySize > 0;
1393 default:
1394 Q_UNREACHABLE_RETURN(false);
1395 }
1396}
1397
1399{
1400 switch (limit) {
1402 return 1;
1404 return caps.maxTextureSize;
1406 return caps.maxDrawBuffers;
1408 // From our perspective. What the GL impl does internally is another
1409 // question, but that's out of our hands and does not concern us here.
1410 return 1;
1412 return 1;
1418 return caps.maxThreadGroupsX;
1420 return caps.maxThreadGroupsY;
1422 return caps.maxThreadGroupsZ;
1424 return 2048;
1426 return int(qMin<qint64>(INT_MAX, caps.maxUniformVectors * qint64(16)));
1428 return caps.maxVertexInputs;
1430 return caps.maxVertexOutputs;
1431 default:
1432 Q_UNREACHABLE_RETURN(0);
1433 }
1434}
1435
1437{
1438 return &nativeHandlesStruct;
1439}
1440
1442{
1443 return driverInfoStruct;
1444}
1445
1447{
1449 result.totalPipelineCreationTime = totalPipelineCreationTime();
1450 return result;
1451}
1452
1454{
1455 if (inFrame && !ofr.active)
1457 else
1458 return ensureContext();
1459}
1460
1462{
1463 if (!ensureContext())
1464 return;
1465
1466 for (uint shader : m_shaderCache)
1467 f->glDeleteShader(shader);
1468
1470
1471 m_pipelineCache.clear();
1472}
1473
1475{
1476 return contextLost;
1477}
1478
1480{
1485 char driver[240];
1486};
1487
1489{
1491
1492 if (m_pipelineCache.isEmpty())
1493 return QByteArray();
1494
1496 memset(&header, 0, sizeof(header));
1497 header.rhiId = pipelineCacheRhiId();
1498 header.arch = quint32(sizeof(void*));
1499 header.programBinaryCount = m_pipelineCache.size();
1500 const size_t driverStrLen = qMin(sizeof(header.driver) - 1, size_t(driverInfoStruct.deviceName.size()));
1501 if (driverStrLen)
1502 memcpy(header.driver, driverInfoStruct.deviceName.constData(), driverStrLen);
1503 header.driver[driverStrLen] = '\0';
1504
1505 const size_t dataOffset = sizeof(header);
1506 size_t dataSize = 0;
1507 for (auto it = m_pipelineCache.cbegin(), end = m_pipelineCache.cend(); it != end; ++it) {
1508 dataSize += sizeof(quint32) + it.key().size()
1509 + sizeof(quint32) + it->data.size()
1510 + sizeof(quint32);
1511 }
1512
1514 char *p = buf.data() + dataOffset;
1515 for (auto it = m_pipelineCache.cbegin(), end = m_pipelineCache.cend(); it != end; ++it) {
1516 const QByteArray key = it.key();
1517 const QByteArray data = it->data;
1518 const quint32 format = it->format;
1519
1520 quint32 i = key.size();
1521 memcpy(p, &i, 4);
1522 p += 4;
1523 memcpy(p, key.constData(), key.size());
1524 p += key.size();
1525
1526 i = data.size();
1527 memcpy(p, &i, 4);
1528 p += 4;
1529 memcpy(p, data.constData(), data.size());
1530 p += data.size();
1531
1532 memcpy(p, &format, 4);
1533 p += 4;
1534 }
1535 Q_ASSERT(p == buf.data() + dataOffset + dataSize);
1536
1537 header.dataSize = quint32(dataSize);
1538 memcpy(buf.data(), &header, sizeof(header));
1539
1540 return buf;
1541}
1542
1544{
1545 if (data.isEmpty())
1546 return;
1547
1548 const size_t headerSize = sizeof(QGles2PipelineCacheDataHeader);
1549 if (data.size() < qsizetype(headerSize)) {
1550 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Invalid blob size (header incomplete)");
1551 return;
1552 }
1553 const size_t dataOffset = headerSize;
1555 memcpy(&header, data.constData(), headerSize);
1556
1557 const quint32 rhiId = pipelineCacheRhiId();
1558 if (header.rhiId != rhiId) {
1559 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
1560 rhiId, header.rhiId);
1561 return;
1562 }
1563 const quint32 arch = quint32(sizeof(void*));
1564 if (header.arch != arch) {
1565 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Architecture does not match (%u, %u)",
1566 arch, header.arch);
1567 return;
1568 }
1569 if (header.programBinaryCount == 0)
1570 return;
1571
1572 const size_t driverStrLen = qMin(sizeof(header.driver) - 1, size_t(driverInfoStruct.deviceName.size()));
1573 if (strncmp(header.driver, driverInfoStruct.deviceName.constData(), driverStrLen)) {
1574 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: OpenGL vendor/renderer/version does not match");
1575 return;
1576 }
1577
1578 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
1579 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Invalid blob size (data incomplete)");
1580 return;
1581 }
1582
1583 m_pipelineCache.clear();
1584
1585 const char *p = data.constData() + dataOffset;
1586 for (quint32 i = 0; i < header.programBinaryCount; ++i) {
1587 quint32 len = 0;
1588 memcpy(&len, p, 4);
1589 p += 4;
1591 memcpy(key.data(), p, len);
1592 p += len;
1593
1594 memcpy(&len, p, 4);
1595 p += 4;
1597 memcpy(data.data(), p, len);
1598 p += len;
1599
1601 memcpy(&format, p, 4);
1602 p += 4;
1603
1604 m_pipelineCache.insert(key, { format, data });
1605 }
1606
1607 qCDebug(QRHI_LOG_INFO, "Seeded pipeline cache with %d program binaries", int(m_pipelineCache.size()));
1608}
1609
1611 int sampleCount, QRhiRenderBuffer::Flags flags,
1612 QRhiTexture::Format backingFormatHint)
1613{
1614 return new QGles2RenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint);
1615}
1616
1618 const QSize &pixelSize, int depth, int arraySize,
1619 int sampleCount, QRhiTexture::Flags flags)
1620{
1621 return new QGles2Texture(this, format, pixelSize, depth, arraySize, sampleCount, flags);
1622}
1623
1625 QRhiSampler::Filter mipmapMode,
1627{
1628 return new QGles2Sampler(this, magFilter, minFilter, mipmapMode, u, v, w);
1629}
1630
1632 QRhiTextureRenderTarget::Flags flags)
1633{
1634 return new QGles2TextureRenderTarget(this, desc, flags);
1635}
1636
1638{
1639 return new QGles2GraphicsPipeline(this);
1640}
1641
1643{
1644 return new QGles2ShaderResourceBindings(this);
1645}
1646
1648{
1649 return new QGles2ComputePipeline(this);
1650}
1651
1653{
1657 const bool pipelineChanged = cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation;
1658
1659 if (pipelineChanged) {
1660 cbD->currentGraphicsPipeline = ps;
1661 cbD->currentComputePipeline = nullptr;
1663
1664 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1666 cmd.args.bindGraphicsPipeline.ps = ps;
1667 }
1668}
1669
1671 int dynamicOffsetCount,
1672 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1673{
1678
1679 if (!srb) {
1680 if (gfxPsD)
1681 srb = gfxPsD->m_shaderResourceBindings;
1682 else
1683 srb = compPsD->m_shaderResourceBindings;
1684 }
1685
1687 if (cbD->passNeedsResourceTracking) {
1689 for (int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1691 switch (b->type) {
1693 // no BufUniformRead / AccessUniform because no real uniform buffers are used
1694 break;
1697 for (int elem = 0; elem < b->u.stex.count; ++elem) {
1698 trackedRegisterTexture(&passResTracker,
1699 QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex),
1702 }
1703 break;
1707 {
1708 QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.simage.tex);
1712 else if (b->type == QRhiShaderResourceBinding::ImageStore)
1714 else
1716 trackedRegisterTexture(&passResTracker, texD, access,
1718 }
1719 break;
1723 {
1724 QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b->u.sbuf.buf);
1728 else if (b->type == QRhiShaderResourceBinding::BufferStore)
1730 else
1732 trackedRegisterBuffer(&passResTracker, bufD, access,
1734 }
1735 break;
1736 default:
1737 break;
1738 }
1739 }
1740 }
1741
1742 bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1743
1744 // The Command::BindShaderResources command generated below is what will
1745 // cause uniforms to be set (glUniformNxx). This needs some special
1746 // handling here in this backend without real uniform buffers, because,
1747 // like in other backends, we optimize out the setShaderResources when the
1748 // srb that was set before is attempted to be set again on the command
1749 // buffer, but that is incorrect if the same srb is now used with another
1750 // pipeline. (because that could mean a glUseProgram not followed by
1751 // up-to-date glUniform calls, i.e. with GL we have a strong dependency
1752 // between the pipeline (== program) and the srb, unlike other APIs) This
1753 // is the reason there is a second level of srb(+generation) tracking in
1754 // the pipeline objects.
1755 if (gfxPsD && (gfxPsD->currentSrb != srb || gfxPsD->currentSrbGeneration != srbD->generation)) {
1756 srbChanged = true;
1757 gfxPsD->currentSrb = srb;
1758 gfxPsD->currentSrbGeneration = srbD->generation;
1759 } else if (compPsD && (compPsD->currentSrb != srb || compPsD->currentSrbGeneration != srbD->generation)) {
1760 srbChanged = true;
1761 compPsD->currentSrb = srb;
1762 compPsD->currentSrbGeneration = srbD->generation;
1763 }
1764
1765 if (srbChanged || cbD->currentSrbGeneration != srbD->generation || srbD->hasDynamicOffset) {
1766 if (gfxPsD) {
1767 cbD->currentGraphicsSrb = srb;
1768 cbD->currentComputeSrb = nullptr;
1769 } else {
1770 cbD->currentGraphicsSrb = nullptr;
1771 cbD->currentComputeSrb = srb;
1772 }
1773 cbD->currentSrbGeneration = srbD->generation;
1774
1775 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1779 cmd.args.bindShaderResources.srb = srb;
1781 if (srbD->hasDynamicOffset) {
1782 if (dynamicOffsetCount < QGles2CommandBuffer::MAX_DYNAMIC_OFFSET_COUNT) {
1783 cmd.args.bindShaderResources.dynamicOffsetCount = dynamicOffsetCount;
1785 for (int i = 0; i < dynamicOffsetCount; ++i) {
1786 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1787 *p++ = uint(dynOfs.first);
1788 *p++ = dynOfs.second;
1789 }
1790 } else {
1791 qWarning("Too many dynamic offsets (%d, max is %d)",
1793 }
1794 }
1795 }
1796}
1797
1799 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
1800 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1801{
1805
1806 for (int i = 0; i < bindingCount; ++i) {
1807 QRhiBuffer *buf = bindings[i].first;
1808 quint32 ofs = bindings[i].second;
1810 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1811
1812 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1815 cmd.args.bindVertexBuffer.buffer = bufD->buffer;
1816 cmd.args.bindVertexBuffer.offset = ofs;
1817 cmd.args.bindVertexBuffer.binding = startBinding + i;
1818
1819 if (cbD->passNeedsResourceTracking) {
1822 }
1823 }
1824
1825 if (indexBuf) {
1826 QGles2Buffer *ibufD = QRHI_RES(QGles2Buffer, indexBuf);
1827 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1828
1829 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1831 cmd.args.bindIndexBuffer.buffer = ibufD->buffer;
1832 cmd.args.bindIndexBuffer.offset = indexOffset;
1833 cmd.args.bindIndexBuffer.type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
1834
1835 if (cbD->passNeedsResourceTracking) {
1838 }
1839 }
1840}
1841
1843{
1846
1847 const std::array<float, 4> r = viewport.viewport();
1848 // A negative width or height is an error. A negative x or y is not.
1849 if (r[2] < 0.0f || r[3] < 0.0f)
1850 return;
1851
1852 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1854 cmd.args.viewport.x = r[0];
1855 cmd.args.viewport.y = r[1];
1856 cmd.args.viewport.w = r[2];
1857 cmd.args.viewport.h = r[3];
1858 cmd.args.viewport.d0 = viewport.minDepth();
1859 cmd.args.viewport.d1 = viewport.maxDepth();
1860}
1861
1863{
1866
1867 const std::array<int, 4> r = scissor.scissor();
1868 // A negative width or height is an error. A negative x or y is not.
1869 if (r[2] < 0 || r[3] < 0)
1870 return;
1871
1872 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1874 cmd.args.scissor.x = r[0];
1875 cmd.args.scissor.y = r[1];
1876 cmd.args.scissor.w = r[2];
1877 cmd.args.scissor.h = r[3];
1878}
1879
1881{
1884
1885 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1887 cmd.args.blendConstants.r = float(c.redF());
1888 cmd.args.blendConstants.g = float(c.greenF());
1889 cmd.args.blendConstants.b = float(c.blueF());
1890 cmd.args.blendConstants.a = float(c.alphaF());
1891}
1892
1894{
1897
1898 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1900 cmd.args.stencilRef.ref = refValue;
1902}
1903
1905 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1906{
1909
1910 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1913 cmd.args.draw.vertexCount = vertexCount;
1914 cmd.args.draw.firstVertex = firstVertex;
1916 cmd.args.draw.baseInstance = firstInstance;
1917}
1918
1920 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1921{
1924
1925 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1928 cmd.args.drawIndexed.indexCount = indexCount;
1929 cmd.args.drawIndexed.firstIndex = firstIndex;
1931 cmd.args.drawIndexed.baseInstance = firstInstance;
1932 cmd.args.drawIndexed.baseVertex = vertexOffset;
1933}
1934
1936{
1937 if (!debugMarkers)
1938 return;
1939
1940 Q_UNUSED(cb);
1941 Q_UNUSED(name);
1942}
1943
1945{
1946 if (!debugMarkers)
1947 return;
1948
1949 Q_UNUSED(cb);
1950}
1951
1953{
1954 if (!debugMarkers)
1955 return;
1956
1957 Q_UNUSED(cb);
1958 Q_UNUSED(msg);
1959}
1960
1962{
1963 Q_UNUSED(cb);
1964 return nullptr;
1965}
1966
1968{
1969 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1970 cmd.cmd = type;
1971}
1972
1974{
1975 if (ofr.active) {
1977 if (!ensureContext())
1978 return;
1979 } else {
1982 return;
1983 }
1984
1986
1989 {
1990 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
1993 }
1994
1996
1997 cbD->resetCommands();
1998
1999 if (vao) {
2000 f->glBindVertexArray(0);
2001 } else {
2002 f->glBindBuffer(GL_ARRAY_BUFFER, 0);
2003 f->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2004 if (caps.compute)
2005 f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2006 }
2007}
2008
2010{
2012 Q_ASSERT(cbD->commands.isEmpty() && cbD->currentPassResTrackerIndex == -1);
2013
2014 cbD->resetCachedState();
2015
2017 // Commands that come after this point need a resource tracker and also
2018 // a BarriersForPass command enqueued. (the ones we had from
2019 // beginPass() are now gone since beginExternal() processed all that
2020 // due to calling executeCommandBuffer()).
2022 }
2023
2025
2026 if (cbD->currentTarget)
2028}
2029
2031{
2032 Q_UNUSED(cb);
2033 return 0;
2034}
2035
2037{
2038 QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
2039 if (!ensureContext(swapChainD->surface))
2041
2042 ctx->handle()->beginFrame();
2043
2044 currentSwapChain = swapChainD;
2045
2047 swapChainD->cb.resetState();
2048
2050
2051 return QRhi::FrameOpSuccess;
2052}
2053
2055{
2056 QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
2057 Q_ASSERT(currentSwapChain == swapChainD);
2058
2060
2061 if (!ensureContext(swapChainD->surface))
2063
2064 executeCommandBuffer(&swapChainD->cb);
2065
2066 if (swapChainD->surface && !flags.testFlag(QRhi::SkipPresent)) {
2067 ctx->swapBuffers(swapChainD->surface);
2069 } else {
2070 f->glFlush();
2071 }
2072
2073 swapChainD->frameCount += 1;
2074 currentSwapChain = nullptr;
2075
2076 ctx->handle()->endFrame();
2077
2078 return QRhi::FrameOpSuccess;
2079}
2080
2082{
2083 if (!ensureContext())
2085
2086 ofr.active = true;
2087
2090
2092 *cb = &ofr.cbWrapper;
2093
2094 return QRhi::FrameOpSuccess;
2095}
2096
2098{
2099 Q_UNUSED(flags);
2101 ofr.active = false;
2102
2104
2105 if (!ensureContext())
2107
2109
2110 // Just as endFrame() does a flush when skipping the swapBuffers(), do it
2111 // here as well. This has the added benefit of playing nice when rendering
2112 // to a texture from a context and then consuming that texture from
2113 // another, sharing context.
2114 f->glFlush();
2115
2116 return QRhi::FrameOpSuccess;
2117}
2118
2120{
2121 if (inFrame) {
2122 if (ofr.active) {
2125 if (!ensureContext())
2129 } else {
2136 }
2137 // Do an actual glFinish(). May seem superfluous, but this is what
2138 // matches most other backends e.g. Vulkan/Metal that do a heavyweight
2139 // wait-for-idle blocking in their finish(). More importantly, this
2140 // allows clients simply call finish() in threaded or shared context
2141 // situations where one explicitly needs to do a glFlush or Finish.
2142 f->glFinish();
2143 }
2144 return QRhi::FrameOpSuccess;
2145}
2146
2148{
2152}
2153
2155{
2160}
2161
2163{
2169}
2170
2172{
2178}
2179
2181{
2182 Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::NoPass); // this is for resource updates only
2183 if (!bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer))
2184 return;
2185
2186 const QGles2Buffer::Access prevAccess = bufD->usageState.access;
2187 if (access == prevAccess)
2188 return;
2189
2190 if (bufferAccessIsWrite(prevAccess)) {
2191 // Generating the minimal barrier set is way too complicated to do
2192 // correctly (prevAccess is overwritten so we won't have proper
2193 // tracking across multiple passes) so setting all barrier bits will do
2194 // for now.
2195 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2198 }
2199
2200 bufD->usageState.access = access;
2201}
2202
2204{
2205 Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::NoPass); // this is for resource updates only
2206 if (!texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
2207 return;
2208
2209 const QGles2Texture::Access prevAccess = texD->usageState.access;
2210 if (access == prevAccess)
2211 return;
2212
2213 if (textureAccessIsWrite(prevAccess)) {
2214 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2217 }
2218
2219 texD->usageState.access = access;
2220}
2221
2223 int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc)
2224{
2226 const bool isCompressed = isCompressedFormat(texD->m_format);
2227 const bool isCubeMap = texD->m_flags.testFlag(QRhiTexture::CubeMap);
2228 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
2229 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
2230 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
2231 const GLenum faceTargetBase = isCubeMap ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
2232 const GLenum effectiveTarget = faceTargetBase + (isCubeMap ? uint(layer) : 0u);
2233 const QPoint dp = subresDesc.destinationTopLeft();
2234 const QByteArray rawData = subresDesc.data();
2235 if (!subresDesc.image().isNull()) {
2236 QImage img = subresDesc.image();
2237 QSize size = img.size();
2238 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2240 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
2241 const QPoint sp = subresDesc.sourceTopLeft();
2242 if (!subresDesc.sourceSize().isEmpty())
2243 size = subresDesc.sourceSize();
2244 img = img.copy(sp.x(), sp.y(), size.width(), size.height());
2245 }
2246 cmd.args.subImage.target = texD->target;
2247 cmd.args.subImage.texture = texD->texture;
2248 cmd.args.subImage.faceTarget = effectiveTarget;
2249 cmd.args.subImage.level = level;
2250 cmd.args.subImage.dx = dp.x();
2251 cmd.args.subImage.dy = is1D && isArray ? layer : dp.y();
2252 cmd.args.subImage.dz = is3D || isArray ? layer : 0;
2253 cmd.args.subImage.w = size.width();
2254 cmd.args.subImage.h = size.height();
2255 cmd.args.subImage.glformat = texD->glformat;
2256 cmd.args.subImage.gltype = texD->gltype;
2257 cmd.args.subImage.rowStartAlign = 4;
2258 cmd.args.subImage.rowLength = 0;
2259 cmd.args.subImage.data = cbD->retainImage(img);
2260 } else if (!rawData.isEmpty() && isCompressed) {
2261 const int depth = qMax(1, texD->m_depth);
2262 const int arraySize = qMax(0, texD->m_arraySize);
2263 if ((texD->flags().testFlag(QRhiTexture::UsedAsCompressedAtlas) || is3D || isArray)
2264 && !texD->zeroInitialized)
2265 {
2266 // Create on first upload since glCompressedTexImage2D cannot take
2267 // nullptr data. We have a rule in the QRhi docs that the first
2268 // upload for a compressed texture must cover the entire image, but
2269 // that is clearly not ideal when building a texture atlas, or when
2270 // having a 3D texture with per-slice data.
2271 quint32 byteSize = 0;
2272 compressedFormatInfo(texD->m_format, texD->m_pixelSize, nullptr, &byteSize, nullptr);
2273 if (is3D)
2274 byteSize *= depth;
2275 if (isArray)
2276 byteSize *= arraySize;
2277 QByteArray zeroBuf(byteSize, 0);
2278 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2280 cmd.args.compressedImage.target = texD->target;
2281 cmd.args.compressedImage.texture = texD->texture;
2282 cmd.args.compressedImage.faceTarget = effectiveTarget;
2285 cmd.args.compressedImage.w = texD->m_pixelSize.width();
2286 cmd.args.compressedImage.h = is1D && isArray ? arraySize : texD->m_pixelSize.height();
2287 cmd.args.compressedImage.depth = is3D ? depth : (isArray ? arraySize : 0);
2288 cmd.args.compressedImage.size = byteSize;
2289 cmd.args.compressedImage.data = cbD->retainData(zeroBuf);
2290 texD->zeroInitialized = true;
2291 }
2292
2293 const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
2294 : subresDesc.sourceSize();
2295 if (texD->specified || texD->zeroInitialized) {
2296 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2300 cmd.args.compressedSubImage.faceTarget = effectiveTarget;
2302 cmd.args.compressedSubImage.dx = dp.x();
2303 cmd.args.compressedSubImage.dy = is1D && isArray ? layer : dp.y();
2304 cmd.args.compressedSubImage.dz = is3D || isArray ? layer : 0;
2305 cmd.args.compressedSubImage.w = size.width();
2306 cmd.args.compressedSubImage.h = size.height();
2308 cmd.args.compressedSubImage.size = rawData.size();
2309 cmd.args.compressedSubImage.data = cbD->retainData(rawData);
2310 } else {
2311 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2313 cmd.args.compressedImage.target = texD->target;
2314 cmd.args.compressedImage.texture = texD->texture;
2315 cmd.args.compressedImage.faceTarget = effectiveTarget;
2318 cmd.args.compressedImage.w = size.width();
2319 cmd.args.compressedImage.h = is1D && isArray ? arraySize : size.height();
2320 cmd.args.compressedImage.depth = is3D ? depth : (isArray ? arraySize : 0);
2321 cmd.args.compressedImage.size = rawData.size();
2322 cmd.args.compressedImage.data = cbD->retainData(rawData);
2323 }
2324 } else if (!rawData.isEmpty()) {
2325 const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
2326 : subresDesc.sourceSize();
2327 quint32 bytesPerLine = 0;
2328 quint32 bytesPerPixel = 0;
2329 textureFormatInfo(texD->m_format, size, &bytesPerLine, nullptr, &bytesPerPixel);
2330 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2332 cmd.args.subImage.target = texD->target;
2333 cmd.args.subImage.texture = texD->texture;
2334 cmd.args.subImage.faceTarget = effectiveTarget;
2335 cmd.args.subImage.level = level;
2336 cmd.args.subImage.dx = dp.x();
2337 cmd.args.subImage.dy = is1D && isArray ? layer : dp.y();
2338 cmd.args.subImage.dz = is3D || isArray ? layer : 0;
2339 cmd.args.subImage.w = size.width();
2340 cmd.args.subImage.h = size.height();
2341 cmd.args.subImage.glformat = texD->glformat;
2342 cmd.args.subImage.gltype = texD->gltype;
2343 // Default unpack alignment (row start alignment
2344 // requirement) is 4. QImage guarantees 4 byte aligned
2345 // row starts, but our raw data here does not.
2346 cmd.args.subImage.rowStartAlign = (bytesPerLine & 3) ? 1 : 4;
2347 if (subresDesc.dataStride() && bytesPerPixel)
2348 cmd.args.subImage.rowLength = subresDesc.dataStride() / bytesPerPixel;
2349 else
2350 cmd.args.subImage.rowLength = 0;
2351 cmd.args.subImage.data = cbD->retainData(rawData);
2352 } else {
2353 qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
2354 }
2355}
2356
2358{
2361
2362 for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
2367 if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
2368 memcpy(bufD->data.data() + u.offset, u.data.constData(), size_t(u.data.size()));
2369 } else {
2371 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2374 cmd.args.bufferSubData.buffer = bufD->buffer;
2376 cmd.args.bufferSubData.size = u.data.size();
2378 }
2382 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
2383 if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
2384 memcpy(bufD->data.data() + u.offset, u.data.constData(), size_t(u.data.size()));
2385 } else {
2387 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2390 cmd.args.bufferSubData.buffer = bufD->buffer;
2392 cmd.args.bufferSubData.size = u.data.size();
2394 }
2397 if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
2398 u.result->data.resize(u.readSize);
2399 memcpy(u.result->data.data(), bufD->data.constData() + u.offset, size_t(u.readSize));
2400 if (u.result->completed)
2401 u.result->completed();
2402 } else {
2403 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2407 cmd.args.getBufferSubData.buffer = bufD->buffer;
2410 }
2411 }
2412 }
2413
2414 for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
2418 for (int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
2419 for (int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
2420 for (const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
2421 enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
2422 }
2423 }
2424 texD->specified = true;
2426 Q_ASSERT(u.src && u.dst);
2429
2432
2433 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
2434 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
2435 // do not translate coordinates, even if sp is bottom-left from gl's pov
2436 const QPoint sp = u.desc.sourceTopLeft();
2437 const QPoint dp = u.desc.destinationTopLeft();
2438
2439 const GLenum srcFaceTargetBase = srcD->m_flags.testFlag(QRhiTexture::CubeMap)
2441 const GLenum dstFaceTargetBase = dstD->m_flags.testFlag(QRhiTexture::CubeMap)
2443
2444 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2446
2447 const bool srcHasZ = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional) || srcD->m_flags.testFlag(QRhiTexture::TextureArray);
2448 const bool dstHasZ = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional) || dstD->m_flags.testFlag(QRhiTexture::TextureArray);
2449 const bool dstIs1dArray = dstD->m_flags.testFlag(QRhiTexture::OneDimensional)
2450 && dstD->m_flags.testFlag(QRhiTexture::TextureArray);
2451
2452 cmd.args.copyTex.srcTarget = srcD->target;
2453 cmd.args.copyTex.srcFaceTarget = srcFaceTargetBase + (srcHasZ ? 0u : uint(u.desc.sourceLayer()));
2454 cmd.args.copyTex.srcTexture = srcD->texture;
2456 cmd.args.copyTex.srcX = sp.x();
2457 cmd.args.copyTex.srcY = sp.y();
2458 cmd.args.copyTex.srcZ = srcHasZ ? u.desc.sourceLayer() : 0;
2459
2460 cmd.args.copyTex.dstTarget = dstD->target;
2461 cmd.args.copyTex.dstFaceTarget = dstFaceTargetBase + (dstHasZ ? 0u : uint(u.desc.destinationLayer()));
2462 cmd.args.copyTex.dstTexture = dstD->texture;
2464 cmd.args.copyTex.dstX = dp.x();
2465 cmd.args.copyTex.dstY = dstIs1dArray ? u.desc.destinationLayer() : dp.y();
2466 cmd.args.copyTex.dstZ = dstHasZ ? u.desc.destinationLayer() : 0;
2467
2468 cmd.args.copyTex.w = copySize.width();
2469 cmd.args.copyTex.h = copySize.height();
2471 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2473 cmd.args.readPixels.result = u.result;
2475 if (texD)
2477 cmd.args.readPixels.texture = texD ? texD->texture : 0;
2478 cmd.args.readPixels.slice3D = -1;
2479 if (texD) {
2480 const QSize readImageSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
2481 cmd.args.readPixels.w = readImageSize.width();
2482 cmd.args.readPixels.h = readImageSize.height();
2483 cmd.args.readPixels.format = texD->m_format;
2484 if (texD->m_flags.testFlag(QRhiTexture::ThreeDimensional)
2485 || texD->m_flags.testFlag(QRhiTexture::TextureArray))
2486 {
2487 cmd.args.readPixels.readTarget = texD->target;
2488 cmd.args.readPixels.slice3D = u.rb.layer();
2489 } else {
2490 const GLenum faceTargetBase = texD->m_flags.testFlag(QRhiTexture::CubeMap)
2492 cmd.args.readPixels.readTarget = faceTargetBase + uint(u.rb.layer());
2493 }
2494 cmd.args.readPixels.level = u.rb.level();
2495 }
2499 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
2501 cmd.args.genMip.target = texD->target;
2502 cmd.args.genMip.texture = texD->texture;
2503 }
2504 }
2505
2506 ud->free();
2507}
2508
2510{
2511 switch (t) {
2513 return GL_TRIANGLES;
2515 return GL_TRIANGLE_STRIP;
2517 return GL_TRIANGLE_FAN;
2519 return GL_LINES;
2521 return GL_LINE_STRIP;
2523 return GL_POINTS;
2525 return GL_PATCHES;
2526 default:
2527 Q_UNREACHABLE_RETURN(GL_TRIANGLES);
2528 }
2529}
2530
2532{
2533 switch (c) {
2535 return GL_FRONT;
2537 return GL_BACK;
2538 default:
2539 Q_UNREACHABLE_RETURN(GL_BACK);
2540 }
2541}
2542
2544{
2545 switch (f) {
2547 return GL_CCW;
2549 return GL_CW;
2550 default:
2551 Q_UNREACHABLE_RETURN(GL_CCW);
2552 }
2553}
2554
2556{
2557 switch (f) {
2559 return GL_ZERO;
2561 return GL_ONE;
2563 return GL_SRC_COLOR;
2565 return GL_ONE_MINUS_SRC_COLOR;
2567 return GL_DST_COLOR;
2569 return GL_ONE_MINUS_DST_COLOR;
2571 return GL_SRC_ALPHA;
2573 return GL_ONE_MINUS_SRC_ALPHA;
2575 return GL_DST_ALPHA;
2577 return GL_ONE_MINUS_DST_ALPHA;
2579 return GL_CONSTANT_COLOR;
2583 return GL_CONSTANT_ALPHA;
2587 return GL_SRC_ALPHA_SATURATE;
2592 qWarning("Unsupported blend factor %d", f);
2593 return GL_ZERO;
2594 default:
2595 Q_UNREACHABLE_RETURN(GL_ZERO);
2596 }
2597}
2598
2600{
2601 switch (op) {
2603 return GL_FUNC_ADD;
2605 return GL_FUNC_SUBTRACT;
2609 return GL_MIN;
2611 return GL_MAX;
2612 default:
2613 Q_UNREACHABLE_RETURN(GL_FUNC_ADD);
2614 }
2615}
2616
2618{
2619 switch (op) {
2621 return GL_NEVER;
2623 return GL_LESS;
2625 return GL_EQUAL;
2627 return GL_LEQUAL;
2629 return GL_GREATER;
2631 return GL_NOTEQUAL;
2633 return GL_GEQUAL;
2635 return GL_ALWAYS;
2636 default:
2637 Q_UNREACHABLE_RETURN(GL_ALWAYS);
2638 }
2639}
2640
2642{
2643 switch (op) {
2645 return GL_ZERO;
2647 return GL_KEEP;
2649 return GL_REPLACE;
2651 return GL_INCR;
2653 return GL_DECR;
2655 return GL_INVERT;
2657 return GL_INCR_WRAP;
2659 return GL_DECR_WRAP;
2660 default:
2661 Q_UNREACHABLE_RETURN(GL_KEEP);
2662 }
2663}
2664
2666{
2667 switch (mode) {
2669 return GL_FILL;
2671 return GL_LINE;
2672 default:
2673 Q_UNREACHABLE_RETURN(GL_FILL);
2674 }
2675}
2676
2678{
2679 switch (f) {
2681 if (m == QRhiSampler::None)
2682 return GL_NEAREST;
2683 else
2684 return m == QRhiSampler::Nearest ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_LINEAR;
2686 if (m == QRhiSampler::None)
2687 return GL_LINEAR;
2688 else
2689 return m == QRhiSampler::Nearest ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR;
2690 default:
2691 Q_UNREACHABLE_RETURN(GL_LINEAR);
2692 }
2693}
2694
2696{
2697 switch (f) {
2699 return GL_NEAREST;
2701 return GL_LINEAR;
2702 default:
2703 Q_UNREACHABLE_RETURN(GL_LINEAR);
2704 }
2705}
2706
2708{
2709 switch (m) {
2711 return GL_REPEAT;
2713 return GL_CLAMP_TO_EDGE;
2715 return GL_MIRRORED_REPEAT;
2716 default:
2717 Q_UNREACHABLE_RETURN(GL_CLAMP_TO_EDGE);
2718 }
2719}
2720
2722{
2723 switch (op) {
2724 case QRhiSampler::Never:
2725 return GL_NEVER;
2726 case QRhiSampler::Less:
2727 return GL_LESS;
2728 case QRhiSampler::Equal:
2729 return GL_EQUAL;
2731 return GL_LEQUAL;
2733 return GL_GREATER;
2735 return GL_NOTEQUAL;
2737 return GL_GEQUAL;
2739 return GL_ALWAYS;
2740 default:
2741 Q_UNREACHABLE_RETURN(GL_NEVER);
2742 }
2743}
2744
2746{
2747 switch (access) {
2760 default:
2761 Q_UNREACHABLE();
2762 break;
2763 }
2765}
2766
2768{
2770 u.layout = 0; // N/A
2771 u.access = bufUsage.access;
2772 u.stage = 0; // N/A
2773 return u;
2774}
2775
2777{
2778 switch (access) {
2791 default:
2792 Q_UNREACHABLE();
2793 break;
2794 }
2796}
2797
2799{
2801 u.layout = 0; // N/A
2802 u.access = texUsage.access;
2803 u.stage = 0; // N/A
2804 return u;
2805}
2806
2808 QGles2Buffer *bufD,
2811{
2813 passResTracker->registerBuffer(bufD, 0, &access, &stage, toPassTrackerUsageState(u));
2815}
2816
2818 QGles2Texture *texD,
2821{
2823 passResTracker->registerTexture(texD, &access, &stage, toPassTrackerUsageState(u));
2825}
2826
2828{
2829 GLenum indexType = GL_UNSIGNED_SHORT;
2834 struct {
2838 int binding = 0;
2840 static const int TRACKED_ATTRIB_COUNT = 16;
2845};
2846
2847// Helper that must be used in executeCommandBuffer() whenever changing the
2848// ARRAY or ELEMENT_ARRAY buffer binding outside of Command::BindVertexBuffer
2849// and Command::BindIndexBuffer.
2852 GLenum target,
2853 GLuint buffer)
2854{
2855 state->currentArrayBuffer = 0;
2856 state->currentElementArrayBuffer = 0;
2857 state->lastBindVertexBuffer.buffer = 0;
2858 f->glBindBuffer(target, buffer);
2859}
2860
2862{
2865
2866 for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) {
2867 const QGles2CommandBuffer::Command &cmd(*it);
2868 switch (cmd.cmd) {
2870 if (caps.coreProfile) {
2871 if (!vao)
2872 f->glGenVertexArrays(1, &vao);
2873 f->glBindVertexArray(vao);
2874 }
2875 break;
2877 if (state.instancedAttributesUsed) {
2879 if (state.nonzeroAttribDivisor[i])
2880 f->glVertexAttribDivisor(GLuint(i), 0);
2881 }
2882 for (int i = CommandBufferExecTrackedState::TRACKED_ATTRIB_COUNT; i <= state.maxUntrackedInstancedAttribute; ++i)
2883 f->glVertexAttribDivisor(GLuint(i), 0);
2884 state.instancedAttributesUsed = false;
2885 }
2886#ifdef Q_OS_WASM
2888 if (state.enabledAttribArrays[i]) {
2889 f->glDisableVertexAttribArray(GLuint(i));
2890 state.enabledAttribArrays[i] = false;
2891 }
2892 }
2893#endif
2894 if (vao)
2895 f->glBindVertexArray(0);
2896 break;
2898 if (vao)
2899 f->glBindVertexArray(vao);
2900 break;
2902 f->glViewport(GLint(cmd.args.viewport.x), GLint(cmd.args.viewport.y), GLsizei(cmd.args.viewport.w), GLsizei(cmd.args.viewport.h));
2903 f->glDepthRangef(cmd.args.viewport.d0, cmd.args.viewport.d1);
2904 break;
2906 f->glScissor(cmd.args.scissor.x, cmd.args.scissor.y, cmd.args.scissor.w, cmd.args.scissor.h);
2907 break;
2909 f->glBlendColor(cmd.args.blendConstants.r, cmd.args.blendConstants.g, cmd.args.blendConstants.b, cmd.args.blendConstants.a);
2910 break;
2912 {
2914 if (psD) {
2915 const GLint ref = GLint(cmd.args.stencilRef.ref);
2916 f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), ref, psD->m_stencilReadMask);
2917 f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), ref, psD->m_stencilReadMask);
2919 } else {
2920 qWarning("No graphics pipeline active for setStencilRef; ignored");
2921 }
2922 }
2923 break;
2925 {
2927 if (psD) {
2928 if (state.lastBindVertexBuffer.ps == psD
2929 && state.lastBindVertexBuffer.buffer == cmd.args.bindVertexBuffer.buffer
2930 && state.lastBindVertexBuffer.offset == cmd.args.bindVertexBuffer.offset
2931 && state.lastBindVertexBuffer.binding == cmd.args.bindVertexBuffer.binding)
2932 {
2933 // The pipeline and so the vertex input layout is
2934 // immutable, no point in issuing the exact same set of
2935 // glVertexAttribPointer again and again for the same buffer.
2936 break;
2937 }
2938 state.lastBindVertexBuffer.ps = psD;
2939 state.lastBindVertexBuffer.buffer = cmd.args.bindVertexBuffer.buffer;
2940 state.lastBindVertexBuffer.offset = cmd.args.bindVertexBuffer.offset;
2941 state.lastBindVertexBuffer.binding = cmd.args.bindVertexBuffer.binding;
2942
2943 if (cmd.args.bindVertexBuffer.buffer != state.currentArrayBuffer) {
2944 state.currentArrayBuffer = cmd.args.bindVertexBuffer.buffer;
2945 // we do not support more than one vertex buffer
2946 f->glBindBuffer(GL_ARRAY_BUFFER, state.currentArrayBuffer);
2947 }
2949 it != itEnd; ++it)
2950 {
2951 const int bindingIdx = it->binding();
2952 if (bindingIdx != cmd.args.bindVertexBuffer.binding)
2953 continue;
2954
2955 const QRhiVertexInputBinding *inputBinding = psD->m_vertexInputLayout.bindingAt(bindingIdx);
2956 const int stride = int(inputBinding->stride());
2957 int size = 1;
2959 bool normalize = false;
2960 switch (it->format()) {
2962 type = GL_FLOAT;
2963 size = 4;
2964 break;
2966 type = GL_FLOAT;
2967 size = 3;
2968 break;
2970 type = GL_FLOAT;
2971 size = 2;
2972 break;
2974 type = GL_FLOAT;
2975 size = 1;
2976 break;
2979 normalize = true;
2980 size = 4;
2981 break;
2984 normalize = true;
2985 size = 2;
2986 break;
2989 normalize = true;
2990 size = 1;
2991 break;
2993 type = GL_UNSIGNED_INT;
2994 size = 4;
2995 break;
2997 type = GL_UNSIGNED_INT;
2998 size = 3;
2999 break;
3001 type = GL_UNSIGNED_INT;
3002 size = 2;
3003 break;
3005 type = GL_UNSIGNED_INT;
3006 size = 1;
3007 break;
3009 type = GL_INT;
3010 size = 4;
3011 break;
3013 type = GL_INT;
3014 size = 3;
3015 break;
3017 type = GL_INT;
3018 size = 2;
3019 break;
3021 type = GL_INT;
3022 size = 1;
3023 break;
3026 size = 4;
3027 break;
3030 size = 3;
3031 break;
3034 size = 2;
3035 break;
3038 size = 1;
3039 break;
3040 default:
3041 break;
3042 }
3043
3044 const int locationIdx = it->location();
3045 quint32 ofs = it->offset() + cmd.args.bindVertexBuffer.offset;
3046 if (type == GL_UNSIGNED_INT || type == GL_INT) {
3047 if (caps.intAttributes) {
3048 f->glVertexAttribIPointer(GLuint(locationIdx), size, type, stride,
3049 reinterpret_cast<const GLvoid *>(quintptr(ofs)));
3050 } else {
3051 qWarning("Current RHI backend does not support IntAttributes. Check supported features.");
3052 // This is a trick to disable this attribute
3054 state.enabledAttribArrays[locationIdx] = true;
3055 }
3056 } else {
3057 f->glVertexAttribPointer(GLuint(locationIdx), size, type, normalize, stride,
3058 reinterpret_cast<const GLvoid *>(quintptr(ofs)));
3059 }
3060 if (locationIdx >= CommandBufferExecTrackedState::TRACKED_ATTRIB_COUNT || !state.enabledAttribArrays[locationIdx]) {
3062 state.enabledAttribArrays[locationIdx] = true;
3063 f->glEnableVertexAttribArray(GLuint(locationIdx));
3064 }
3066 f->glVertexAttribDivisor(GLuint(locationIdx), inputBinding->instanceStepRate());
3068 state.nonzeroAttribDivisor[locationIdx] = true;
3069 else
3070 state.maxUntrackedInstancedAttribute = qMax(state.maxUntrackedInstancedAttribute, locationIdx);
3071 state.instancedAttributesUsed = true;
3073 && state.nonzeroAttribDivisor[locationIdx])
3075 && locationIdx <= state.maxUntrackedInstancedAttribute))
3076 {
3077 f->glVertexAttribDivisor(GLuint(locationIdx), 0);
3079 state.nonzeroAttribDivisor[locationIdx] = false;
3080 }
3081 }
3082 } else {
3083 qWarning("No graphics pipeline active for setVertexInput; ignored");
3084 }
3085 }
3086 break;
3088 state.indexType = cmd.args.bindIndexBuffer.type;
3089 state.indexStride = state.indexType == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32);
3090 state.indexOffset = cmd.args.bindIndexBuffer.offset;
3091 if (state.currentElementArrayBuffer != cmd.args.bindIndexBuffer.buffer) {
3092 state.currentElementArrayBuffer = cmd.args.bindIndexBuffer.buffer;
3093 f->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state.currentElementArrayBuffer);
3094 }
3095 break;
3097 {
3099 if (psD) {
3100 if (cmd.args.draw.instanceCount == 1 || !caps.instancing) {
3101 f->glDrawArrays(psD->drawMode, GLint(cmd.args.draw.firstVertex), GLsizei(cmd.args.draw.vertexCount));
3102 } else {
3103 f->glDrawArraysInstanced(psD->drawMode, GLint(cmd.args.draw.firstVertex), GLsizei(cmd.args.draw.vertexCount),
3105 }
3106 } else {
3107 qWarning("No graphics pipeline active for draw; ignored");
3108 }
3109 }
3110 break;
3112 {
3114 if (psD) {
3115 const GLvoid *ofs = reinterpret_cast<const GLvoid *>(
3116 quintptr(cmd.args.drawIndexed.firstIndex * state.indexStride + state.indexOffset));
3117 if (cmd.args.drawIndexed.instanceCount == 1 || !caps.instancing) {
3118 if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
3119 f->glDrawElementsBaseVertex(psD->drawMode,
3121 state.indexType,
3122 ofs,
3124 } else {
3125 f->glDrawElements(psD->drawMode,
3127 state.indexType,
3128 ofs);
3129 }
3130 } else {
3131 if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
3132 f->glDrawElementsInstancedBaseVertex(psD->drawMode,
3134 state.indexType,
3135 ofs,
3138 } else {
3139 f->glDrawElementsInstanced(psD->drawMode,
3141 state.indexType,
3142 ofs,
3144 }
3145 }
3146 } else {
3147 qWarning("No graphics pipeline active for drawIndexed; ignored");
3148 }
3149 }
3150 break;
3153 break;
3161 break;
3163 {
3165 if (cmd.args.bindFramebuffer.fbo) {
3166 f->glBindFramebuffer(GL_FRAMEBUFFER, cmd.args.bindFramebuffer.fbo);
3167 const int colorAttCount = cmd.args.bindFramebuffer.colorAttCount;
3168 bufs.append(colorAttCount > 0 ? GL_COLOR_ATTACHMENT0 : GL_NONE);
3169 if (caps.maxDrawBuffers > 1) {
3170 for (int i = 1; i < colorAttCount; ++i)
3171 bufs.append(GL_COLOR_ATTACHMENT0 + uint(i));
3172 }
3173 } else {
3174 f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
3176 bufs.append(GL_BACK_RIGHT);
3177 else
3178 bufs.append(caps.gles ? GL_BACK : GL_BACK_LEFT);
3179 }
3181 f->glDrawBuffers(bufs.count(), bufs.constData());
3183 if (cmd.args.bindFramebuffer.srgb)
3184 f->glEnable(GL_FRAMEBUFFER_SRGB);
3185 else
3186 f->glDisable(GL_FRAMEBUFFER_SRGB);
3187 }
3188 }
3189 break;
3191 f->glDisable(GL_SCISSOR_TEST);
3192 if (cmd.args.clear.mask & GL_COLOR_BUFFER_BIT) {
3193 f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3194 f->glClearColor(cmd.args.clear.c[0], cmd.args.clear.c[1], cmd.args.clear.c[2], cmd.args.clear.c[3]);
3195 }
3196 if (cmd.args.clear.mask & GL_DEPTH_BUFFER_BIT) {
3197 f->glDepthMask(GL_TRUE);
3198 f->glClearDepthf(cmd.args.clear.d);
3199 }
3200 if (cmd.args.clear.mask & GL_STENCIL_BUFFER_BIT) {
3201 f->glStencilMask(0xFF);
3202 f->glClearStencil(GLint(cmd.args.clear.s));
3203 }
3204 f->glClear(cmd.args.clear.mask);
3205 cbD->graphicsPassState.reset(); // altered depth/color write, invalidate in order to avoid confusing the state tracking
3206 break;
3209 f->glBufferSubData(cmd.args.bufferSubData.target, cmd.args.bufferSubData.offset, cmd.args.bufferSubData.size,
3210 cmd.args.bufferSubData.data);
3211 break;
3213 {
3216 if (caps.gles) {
3217 if (caps.properMapBuffer) {
3218 void *p = f->glMapBufferRange(cmd.args.getBufferSubData.target,
3222 if (p) {
3223 result->data.resize(cmd.args.getBufferSubData.size);
3224 memcpy(result->data.data(), p, size_t(cmd.args.getBufferSubData.size));
3225 f->glUnmapBuffer(cmd.args.getBufferSubData.target);
3226 }
3227 }
3228 } else {
3229 result->data.resize(cmd.args.getBufferSubData.size);
3230 f->glGetBufferSubData(cmd.args.getBufferSubData.target,
3233 result->data.data());
3234 }
3235 if (result->completed)
3236 result->completed();
3237 }
3238 break;
3240 {
3241 GLuint fbo;
3242 f->glGenFramebuffers(1, &fbo);
3243 f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3247 f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cmd.args.copyTex.srcTexture,
3249 } else if (cmd.args.copyTex.srcTarget == GL_TEXTURE_1D) {
3250 glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3252 cmd.args.copyTex.srcLevel);
3253 } else {
3254 f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3256 }
3257 f->glBindTexture(cmd.args.copyTex.dstTarget, cmd.args.copyTex.dstTexture);
3259 f->glCopyTexSubImage3D(cmd.args.copyTex.dstTarget, cmd.args.copyTex.dstLevel,
3261 cmd.args.copyTex.srcX, cmd.args.copyTex.srcY,
3262 cmd.args.copyTex.w, cmd.args.copyTex.h);
3263 } else if (cmd.args.copyTex.dstTarget == GL_TEXTURE_1D) {
3264 glCopyTexSubImage1D(cmd.args.copyTex.dstTarget, cmd.args.copyTex.dstLevel,
3265 cmd.args.copyTex.dstX, cmd.args.copyTex.srcX,
3266 cmd.args.copyTex.srcY, cmd.args.copyTex.w);
3267 } else {
3268 f->glCopyTexSubImage2D(cmd.args.copyTex.dstFaceTarget, cmd.args.copyTex.dstLevel,
3269 cmd.args.copyTex.dstX, cmd.args.copyTex.dstY,
3270 cmd.args.copyTex.srcX, cmd.args.copyTex.srcY,
3271 cmd.args.copyTex.w, cmd.args.copyTex.h);
3272 }
3273 f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
3274 f->glDeleteFramebuffers(1, &fbo);
3275 }
3276 break;
3278 {
3280 GLuint tex = cmd.args.readPixels.texture;
3281 GLuint fbo = 0;
3282 int mipLevel = 0;
3283 if (tex) {
3284 result->pixelSize = QSize(cmd.args.readPixels.w, cmd.args.readPixels.h);
3285 result->format = cmd.args.readPixels.format;
3286 mipLevel = cmd.args.readPixels.level;
3287 if (mipLevel == 0 || caps.nonBaseLevelFramebufferTexture) {
3288 f->glGenFramebuffers(1, &fbo);
3289 f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3290 if (cmd.args.readPixels.slice3D >= 0) {
3291 f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3292 tex, mipLevel, cmd.args.readPixels.slice3D);
3293 } else if (cmd.args.readPixels.readTarget == GL_TEXTURE_1D) {
3294 glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3295 cmd.args.readPixels.readTarget, tex, mipLevel);
3296 } else {
3297 f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3298 cmd.args.readPixels.readTarget, tex, mipLevel);
3299 }
3300 }
3301 } else {
3302 result->pixelSize = currentSwapChain->pixelSize;
3303 result->format = QRhiTexture::RGBA8;
3304 // readPixels handles multisample resolving implicitly
3305 }
3306 const int w = result->pixelSize.width();
3307 const int h = result->pixelSize.height();
3308 if (mipLevel == 0 || caps.nonBaseLevelFramebufferTexture) {
3309 // With GLES, GL_RGBA is the only mandated readback format, so stick with it.
3310 // (and that's why we return false for the ReadBackAnyTextureFormat feature)
3311 if (result->format == QRhiTexture::R8 || result->format == QRhiTexture::RED_OR_ALPHA8) {
3312 result->data.resize(w * h);
3313 QByteArray tmpBuf;
3314 tmpBuf.resize(w * h * 4);
3315 f->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, tmpBuf.data());
3316 const quint8 *srcBase = reinterpret_cast<const quint8 *>(tmpBuf.constData());
3317 quint8 *dstBase = reinterpret_cast<quint8 *>(result->data.data());
3318 const int componentIndex = isFeatureSupported(QRhi::RedOrAlpha8IsRed) ? 0 : 3;
3319 for (int y = 0; y < h; ++y) {
3320 const quint8 *src = srcBase + y * w * 4;
3321 quint8 *dst = dstBase + y * w;
3322 int count = w;
3323 while (count-- > 0) {
3324 *dst++ = src[componentIndex];
3325 src += 4;
3326 }
3327 }
3328 } else {
3329 switch (result->format) {
3330 // For floating point formats try it because this can be
3331 // relevant for some use cases; if it works, then fine, if
3332 // not, there's nothing we can do.
3334 result->data.resize(w * h * 8);
3335 f->glReadPixels(0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, result->data.data());
3336 break;
3338 result->data.resize(w * h * 16);
3339 f->glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, result->data.data());
3340 break;
3342 result->data.resize(w * h * 4);
3343 f->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, result->data.data());
3344 break;
3345 default:
3346 result->data.resize(w * h * 4);
3347 f->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, result->data.data());
3348 break;
3349 }
3350 }
3351 } else {
3352 result->data.resize(w * h * 4);
3353 result->data.fill('\0');
3354 }
3355 if (fbo) {
3356 f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
3357 f->glDeleteFramebuffers(1, &fbo);
3358 }
3359 if (result->completed)
3360 result->completed();
3361 }
3362 break;
3364 f->glBindTexture(cmd.args.subImage.target, cmd.args.subImage.texture);
3365 if (cmd.args.subImage.rowStartAlign != 4)
3366 f->glPixelStorei(GL_UNPACK_ALIGNMENT, cmd.args.subImage.rowStartAlign);
3367 if (cmd.args.subImage.rowLength != 0)
3368 f->glPixelStorei(GL_UNPACK_ROW_LENGTH, cmd.args.subImage.rowLength);
3370 f->glTexSubImage3D(cmd.args.subImage.target, cmd.args.subImage.level,
3371 cmd.args.subImage.dx, cmd.args.subImage.dy, cmd.args.subImage.dz,
3372 cmd.args.subImage.w, cmd.args.subImage.h, 1,
3374 cmd.args.subImage.data);
3375 } else if (cmd.args.subImage.target == GL_TEXTURE_1D) {
3376 glTexSubImage1D(cmd.args.subImage.target, cmd.args.subImage.level,
3377 cmd.args.subImage.dx, cmd.args.subImage.w,
3379 cmd.args.subImage.data);
3380 } else {
3381 f->glTexSubImage2D(cmd.args.subImage.faceTarget, cmd.args.subImage.level,
3382 cmd.args.subImage.dx, cmd.args.subImage.dy,
3383 cmd.args.subImage.w, cmd.args.subImage.h,
3385 cmd.args.subImage.data);
3386 }
3387 if (cmd.args.subImage.rowStartAlign != 4)
3388 f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
3389 if (cmd.args.subImage.rowLength != 0)
3390 f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
3391 break;
3393 f->glBindTexture(cmd.args.compressedImage.target, cmd.args.compressedImage.texture);
3395 f->glCompressedTexImage3D(cmd.args.compressedImage.target, cmd.args.compressedImage.level,
3399 } else if (cmd.args.compressedImage.target == GL_TEXTURE_1D) {
3400 glCompressedTexImage1D(
3404 } else {
3405 f->glCompressedTexImage2D(cmd.args.compressedImage.faceTarget, cmd.args.compressedImage.level,
3409 }
3410 break;
3414 f->glCompressedTexSubImage3D(cmd.args.compressedSubImage.target, cmd.args.compressedSubImage.level,
3419 } else if (cmd.args.compressedImage.target == GL_TEXTURE_1D) {
3420 glCompressedTexSubImage1D(
3425 } else {
3426 f->glCompressedTexSubImage2D(cmd.args.compressedSubImage.faceTarget, cmd.args.compressedSubImage.level,
3431 }
3432 break;
3434 {
3435 // Altering the scissor state, so reset the stored state, although
3436 // not strictly required as long as blit is done in endPass() only.
3437 cbD->graphicsPassState.reset();
3438 f->glDisable(GL_SCISSOR_TEST);
3439 GLuint fbo[2];
3440 f->glGenFramebuffers(2, fbo);
3441 f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[0]);
3442 f->glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3444 f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]);
3446 f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3450 } else {
3453 }
3454 f->glBlitFramebuffer(0, 0, cmd.args.blitFromRenderbuffer.w, cmd.args.blitFromRenderbuffer.h,
3456 GL_COLOR_BUFFER_BIT,
3457 GL_NEAREST); // Qt 5 used Nearest when resolving samples, stick to that
3458 f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
3459 f->glDeleteFramebuffers(2, fbo);
3460 }
3461 break;
3463 {
3464 // Altering the scissor state, so reset the stored state, although
3465 // not strictly required as long as blit is done in endPass() only.
3466 cbD->graphicsPassState.reset();
3467 f->glDisable(GL_SCISSOR_TEST);
3468 GLuint fbo[2];
3469 f->glGenFramebuffers(2, fbo);
3470 f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[0]);
3472 f->glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3476 } else {
3479 }
3480 f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]);
3482 f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3486 } else {
3489 }
3490 f->glBlitFramebuffer(0, 0, cmd.args.blitFromTexture.w, cmd.args.blitFromTexture.h,
3491 0, 0, cmd.args.blitFromTexture.w, cmd.args.blitFromTexture.h,
3492 GL_COLOR_BUFFER_BIT,
3493 GL_NEAREST); // Qt 5 used Nearest when resolving samples, stick to that
3494 f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
3495 f->glDeleteFramebuffers(2, fbo);
3496 }
3497 break;
3499 f->glBindTexture(cmd.args.genMip.target, cmd.args.genMip.texture);
3500 f->glGenerateMipmap(cmd.args.genMip.target);
3501 break;
3503 {
3505 f->glUseProgram(psD->program);
3506 }
3507 break;
3509 f->glDispatchCompute(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z);
3510 break;
3512 {
3513 if (!caps.compute)
3514 break;
3515 GLbitfield barriers = 0;
3517 // we only care about after-write, not any other accesses, and
3518 // cannot tell if something was written in a shader several passes
3519 // ago: now the previously written resource may be used with an
3520 // access that was not in the previous passes, result in a missing
3521 // barrier in theory. Hence setting all barrier bits whenever
3522 // something previously written is used for the first time in a
3523 // subsequent pass.
3524 for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
3525 QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access);
3526 if (bufferAccessIsWrite(accessBeforePass))
3527 barriers |= barriersForBuffer();
3528 }
3529 for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
3530 QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access);
3531 if (textureAccessIsWrite(accessBeforePass))
3532 barriers |= barriersForTexture();
3533 }
3534 if (barriers)
3535 f->glMemoryBarrier(barriers);
3536 }
3537 break;
3539 if (caps.compute)
3540 f->glMemoryBarrier(cmd.args.barrier.barriers);
3541 break;
3542 default:
3543 break;
3544 }
3545 }
3546 if (state.instancedAttributesUsed) {
3548 if (state.nonzeroAttribDivisor[i])
3549 f->glVertexAttribDivisor(GLuint(i), 0);
3550 }
3551 for (int i = CommandBufferExecTrackedState::TRACKED_ATTRIB_COUNT; i <= state.maxUntrackedInstancedAttribute; ++i)
3552 f->glVertexAttribDivisor(GLuint(i), 0);
3553 }
3554}
3555
3557{
3559 const bool forceUpdate = !state.valid;
3560 state.valid = true;
3561
3562 const bool scissor = psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor);
3563 if (forceUpdate || scissor != state.scissor) {
3564 state.scissor = scissor;
3565 if (scissor)
3566 f->glEnable(GL_SCISSOR_TEST);
3567 else
3568 f->glDisable(GL_SCISSOR_TEST);
3569 }
3570
3571 const bool cullFace = psD->m_cullMode != QRhiGraphicsPipeline::None;
3572 const GLenum cullMode = cullFace ? toGlCullMode(psD->m_cullMode) : GL_NONE;
3573 if (forceUpdate || cullFace != state.cullFace || cullMode != state.cullMode) {
3574 state.cullFace = cullFace;
3575 state.cullMode = cullMode;
3576 if (cullFace) {
3577 f->glEnable(GL_CULL_FACE);
3578 f->glCullFace(cullMode);
3579 } else {
3580 f->glDisable(GL_CULL_FACE);
3581 }
3582 }
3583
3584 const GLenum frontFace = toGlFrontFace(psD->m_frontFace);
3585 if (forceUpdate || frontFace != state.frontFace) {
3586 state.frontFace = frontFace;
3587 f->glFrontFace(frontFace);
3588 }
3589
3590 const GLenum polygonMode = toGlPolygonMode(psD->m_polygonMode);
3591 if (glPolygonMode && (forceUpdate || polygonMode != state.polygonMode)) {
3592 state.polygonMode = polygonMode;
3593 glPolygonMode(GL_FRONT_AND_BACK, polygonMode);
3594 }
3595
3596 if (!psD->m_targetBlends.isEmpty()) {
3597 // We do not have MRT support here, meaning all targets use the blend
3598 // params from the first one. This is technically incorrect, even if
3599 // nothing in Qt relies on it. However, considering that
3600 // glBlendFuncSeparatei is only available in GL 4.0+ and GLES 3.2+, we
3601 // may just live with this for now because no point in bothering if it
3602 // won't be usable on many GLES (3.1 or 3.0) systems.
3603 const QRhiGraphicsPipeline::TargetBlend &targetBlend(psD->m_targetBlends.first());
3604
3606 targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::R),
3607 targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::G),
3608 targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::B),
3609 targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::A)
3610 };
3611 if (forceUpdate || colorMask != state.colorMask) {
3612 state.colorMask = colorMask;
3613 f->glColorMask(colorMask.r, colorMask.g, colorMask.b, colorMask.a);
3614 }
3615
3616 const bool blendEnabled = targetBlend.enable;
3618 toGlBlendFactor(targetBlend.srcColor),
3619 toGlBlendFactor(targetBlend.dstColor),
3620 toGlBlendFactor(targetBlend.srcAlpha),
3621 toGlBlendFactor(targetBlend.dstAlpha),
3622 toGlBlendOp(targetBlend.opColor),
3623 toGlBlendOp(targetBlend.opAlpha)
3624 };
3625 if (forceUpdate || blendEnabled != state.blendEnabled || (blendEnabled && blend != state.blend)) {
3626 state.blendEnabled = blendEnabled;
3627 if (blendEnabled) {
3628 state.blend = blend;
3629 f->glEnable(GL_BLEND);
3630 f->glBlendFuncSeparate(blend.srcColor, blend.dstColor, blend.srcAlpha, blend.dstAlpha);
3631 f->glBlendEquationSeparate(blend.opColor, blend.opAlpha);
3632 } else {
3633 f->glDisable(GL_BLEND);
3634 }
3635 }
3636 } else {
3637 const QGles2CommandBuffer::GraphicsPassState::ColorMask colorMask = { true, true, true, true };
3638 if (forceUpdate || colorMask != state.colorMask) {
3639 state.colorMask = colorMask;
3640 f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3641 }
3642 const bool blendEnabled = false;
3643 if (forceUpdate || blendEnabled != state.blendEnabled) {
3644 state.blendEnabled = blendEnabled;
3645 f->glDisable(GL_BLEND);
3646 }
3647 }
3648
3649 const bool depthTest = psD->m_depthTest;
3650 if (forceUpdate || depthTest != state.depthTest) {
3651 state.depthTest = depthTest;
3652 if (depthTest)
3653 f->glEnable(GL_DEPTH_TEST);
3654 else
3655 f->glDisable(GL_DEPTH_TEST);
3656 }
3657
3658 const bool depthWrite = psD->m_depthWrite;
3659 if (forceUpdate || depthWrite != state.depthWrite) {
3660 state.depthWrite = depthWrite;
3661 f->glDepthMask(depthWrite);
3662 }
3663
3664 const GLenum depthFunc = toGlCompareOp(psD->m_depthOp);
3665 if (forceUpdate || depthFunc != state.depthFunc) {
3666 state.depthFunc = depthFunc;
3667 f->glDepthFunc(depthFunc);
3668 }
3669
3670 const bool stencilTest = psD->m_stencilTest;
3671 const GLuint stencilReadMask = psD->m_stencilReadMask;
3672 const GLuint stencilWriteMask = psD->m_stencilWriteMask;
3678 };
3684 };
3685 if (forceUpdate || stencilTest != state.stencilTest
3686 || (stencilTest
3687 && (stencilReadMask != state.stencilReadMask || stencilWriteMask != state.stencilWriteMask
3688 || stencilFront != state.stencil[0] || stencilBack != state.stencil[1])))
3689 {
3690 state.stencilTest = stencilTest;
3691 if (stencilTest) {
3692 state.stencilReadMask = stencilReadMask;
3693 state.stencilWriteMask = stencilWriteMask;
3694 state.stencil[0] = stencilFront;
3695 state.stencil[1] = stencilBack;
3696
3697 f->glEnable(GL_STENCIL_TEST);
3698
3699 f->glStencilFuncSeparate(GL_FRONT, stencilFront.func, state.dynamic.stencilRef, stencilReadMask);
3700 f->glStencilOpSeparate(GL_FRONT, stencilFront.failOp, stencilFront.zfailOp, stencilFront.zpassOp);
3701 f->glStencilMaskSeparate(GL_FRONT, stencilWriteMask);
3702
3703 f->glStencilFuncSeparate(GL_BACK, stencilBack.func, state.dynamic.stencilRef, stencilReadMask);
3704 f->glStencilOpSeparate(GL_BACK, stencilBack.failOp, stencilBack.zfailOp, stencilBack.zpassOp);
3705 f->glStencilMaskSeparate(GL_BACK, stencilWriteMask);
3706 } else {
3707 f->glDisable(GL_STENCIL_TEST);
3708 }
3709 }
3710
3711 const bool polyOffsetFill = psD->m_depthBias != 0 || !qFuzzyIsNull(psD->m_slopeScaledDepthBias);
3712 const float polyOffsetFactor = psD->m_slopeScaledDepthBias;
3713 const float polyOffsetUnits = psD->m_depthBias;
3714 if (forceUpdate || state.polyOffsetFill != polyOffsetFill
3715 || polyOffsetFactor != state.polyOffsetFactor || polyOffsetUnits != state.polyOffsetUnits)
3716 {
3717 state.polyOffsetFill = polyOffsetFill;
3718 state.polyOffsetFactor = polyOffsetFactor;
3719 state.polyOffsetUnits = polyOffsetUnits;
3720 if (polyOffsetFill) {
3721 f->glPolygonOffset(polyOffsetFactor, polyOffsetUnits);
3722 f->glEnable(GL_POLYGON_OFFSET_FILL);
3723 } else {
3724 f->glDisable(GL_POLYGON_OFFSET_FILL);
3725 }
3726 }
3727
3729 const float lineWidth = psD->m_lineWidth;
3730 if (forceUpdate || lineWidth != state.lineWidth) {
3731 state.lineWidth = lineWidth;
3732 f->glLineWidth(lineWidth);
3733 }
3734 }
3735
3737 const int cpCount = psD->m_patchControlPointCount;
3738 if (forceUpdate || cpCount != state.cpCount) {
3739 state.cpCount = cpCount;
3740 f->glPatchParameteri(GL_PATCH_VERTICES, qMax(1, cpCount));
3741 }
3742 }
3743
3744 f->glUseProgram(psD->program);
3745}
3746
3747template <typename T>
3748static inline void qrhi_std140_to_packed(T *dst, int vecSize, int elemCount, const void *src)
3749{
3750 const T *p = reinterpret_cast<const T *>(src);
3751 for (int i = 0; i < elemCount; ++i) {
3752 for (int j = 0; j < vecSize; ++j)
3753 dst[vecSize * i + j] = *p++;
3754 p += 4 - vecSize;
3755 }
3756}
3757
3759 void *ps, uint psGeneration, int glslLocation,
3760 int *texUnit, bool *activeTexUnitAltered)
3761{
3762 const bool samplerStateValid = texD->samplerState == samplerD->d;
3763 const bool cachedStateInRange = *texUnit < 16;
3764 bool updateTextureBinding = true;
3765 if (samplerStateValid && cachedStateInRange) {
3766 // If we already encountered the same texture with
3767 // the same pipeline for this texture unit in the
3768 // current pass, then the shader program already
3769 // has the uniform set. As in a 3D scene one model
3770 // often has more than one associated texture map,
3771 // the savings here can become significant,
3772 // depending on the scene.
3773 if (cbD->textureUnitState[*texUnit].ps == ps
3774 && cbD->textureUnitState[*texUnit].psGeneration == psGeneration
3775 && cbD->textureUnitState[*texUnit].texture == texD->texture)
3776 {
3777 updateTextureBinding = false;
3778 }
3779 }
3780 if (updateTextureBinding) {
3781 f->glActiveTexture(GL_TEXTURE0 + uint(*texUnit));
3782 *activeTexUnitAltered = true;
3783 f->glBindTexture(texD->target, texD->texture);
3784 f->glUniform1i(glslLocation, *texUnit);
3785 if (cachedStateInRange) {
3786 cbD->textureUnitState[*texUnit].ps = ps;
3787 cbD->textureUnitState[*texUnit].psGeneration = psGeneration;
3788 cbD->textureUnitState[*texUnit].texture = texD->texture;
3789 }
3790 }
3791 ++(*texUnit);
3792 if (!samplerStateValid) {
3793 f->glTexParameteri(texD->target, GL_TEXTURE_MIN_FILTER, GLint(samplerD->d.glminfilter));
3794 f->glTexParameteri(texD->target, GL_TEXTURE_MAG_FILTER, GLint(samplerD->d.glmagfilter));
3795 f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_S, GLint(samplerD->d.glwraps));
3796 f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_T, GLint(samplerD->d.glwrapt));
3797 if (caps.texture3D)
3798 f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_R, GLint(samplerD->d.glwrapr));
3800 if (samplerD->d.gltexcomparefunc != GL_NEVER) {
3802 f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_FUNC, GLint(samplerD->d.gltexcomparefunc));
3803 } else {
3804 f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
3805 }
3806 }
3807 texD->samplerState = samplerD->d;
3808 }
3809}
3810
3812 QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs,
3814 const uint *dynOfsPairs, int dynOfsCount)
3815{
3817 int texUnit = 1; // start from unit 1, keep 0 for resource mgmt stuff to avoid clashes
3818 bool activeTexUnitAltered = false;
3819 union data32_t {
3820 float f;
3821 qint32 i;
3822 };
3824 QGles2UniformDescriptionVector &uniforms(maybeGraphicsPs ? QRHI_RES(QGles2GraphicsPipeline, maybeGraphicsPs)->uniforms
3825 : QRHI_RES(QGles2ComputePipeline, maybeComputePs)->uniforms);
3826 QGles2UniformState *uniformState = maybeGraphicsPs ? QRHI_RES(QGles2GraphicsPipeline, maybeGraphicsPs)->uniformState
3827 : QRHI_RES(QGles2ComputePipeline, maybeComputePs)->uniformState;
3828 struct SeparateTexture {
3830 int binding;
3831 int elem;
3832 };
3833 QVarLengthArray<SeparateTexture, 8> separateTextureBindings;
3834 struct SeparateSampler {
3836 int binding;
3837 };
3838 QVarLengthArray<SeparateSampler, 4> separateSamplerBindings;
3839
3840 for (int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
3842
3843 switch (b->type) {
3845 {
3846 int viewOffset = b->u.ubuf.offset;
3847 for (int j = 0; j < dynOfsCount; ++j) {
3848 if (dynOfsPairs[2 * j] == uint(b->binding)) {
3849 viewOffset = int(dynOfsPairs[2 * j + 1]);
3850 break;
3851 }
3852 }
3853 QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b->u.ubuf.buf);
3854 const char *bufView = bufD->data.constData() + viewOffset;
3855 for (const QGles2UniformDescription &uniform : std::as_const(uniforms)) {
3856 if (uniform.binding == b->binding) {
3857 // in a uniform buffer everything is at least 4 byte aligned
3858 // so this should not cause unaligned reads
3859 const void *src = bufView + uniform.offset;
3860
3861#ifndef QT_NO_DEBUG
3862 if (uniform.arrayDim > 0
3863 && uniform.type != QShaderDescription::Float
3864 && uniform.type != QShaderDescription::Vec2
3865 && uniform.type != QShaderDescription::Vec3
3866 && uniform.type != QShaderDescription::Vec4
3867 && uniform.type != QShaderDescription::Int
3868 && uniform.type != QShaderDescription::Int2
3869 && uniform.type != QShaderDescription::Int3
3870 && uniform.type != QShaderDescription::Int4
3871 && uniform.type != QShaderDescription::Mat3
3872 && uniform.type != QShaderDescription::Mat4)
3873 {
3874 qWarning("Uniform with buffer binding %d, buffer offset %d, type %d is an array, "
3875 "but arrays are only supported for float, vec2, vec3, vec4, int, "
3876 "ivec2, ivec3, ivec4, mat3 and mat4. "
3877 "Only the first element will be set.",
3878 uniform.binding, uniform.offset, uniform.type);
3879 }
3880#endif
3881
3882 // Our input is an std140 layout uniform block. See
3883 // "Standard Uniform Block Layout" in section 7.6.2.2 of
3884 // the OpenGL spec. This has some peculiar alignment
3885 // requirements, which is not what glUniform* wants. Hence
3886 // the unpacking/repacking for arrays and certain types.
3887
3888 switch (uniform.type) {
3890 {
3891 const int elemCount = uniform.arrayDim;
3892 if (elemCount < 1) {
3893 const float v = *reinterpret_cast<const float *>(src);
3894 if (uniform.glslLocation <= QGles2UniformState::MAX_TRACKED_LOCATION) {
3895 QGles2UniformState &thisUniformState(uniformState[uniform.glslLocation]);
3896 if (thisUniformState.componentCount != 1 || thisUniformState.v[0] != v) {
3897 thisUniformState.componentCount = 1;
3898 thisUniformState.v[0] = v;
3899 f->glUniform1f(uniform.glslLocation, v);
3900 }
3901 } else {
3902 f->glUniform1f(uniform.glslLocation, v);
3903 }
3904 } else {
3905 // input is 16 bytes per element as per std140, have to convert to packed
3906 packedArray.resize(elemCount);
3907 qrhi_std140_to_packed(&packedArray.data()->f, 1, elemCount, src);
3908 f->glUniform1fv(uniform.glslLocation, elemCount, &packedArray.constData()->f);
3909 }
3910 }
3911 break;
3913 {
3914 const int elemCount = uniform.arrayDim;
3915 if (elemCount < 1) {
3916 const float *v = reinterpret_cast<const float *>(src);
3917 if (uniform.glslLocation <= QGles2UniformState::MAX_TRACKED_LOCATION) {
3918 QGles2UniformState &thisUniformState(uniformState[uniform.glslLocation]);
3919 if (thisUniformState.componentCount != 2
3920 || thisUniformState.v[0] != v[0]
3921 || thisUniformState.v[1] != v[1])
3922 {
3923 thisUniformState.componentCount = 2;
3924 thisUniformState.v[0] = v[0];
3925 thisUniformState.v[1] = v[1];
3926 f->glUniform2fv(uniform.glslLocation, 1, v);
3927 }
3928 } else {
3929 f->glUniform2fv(uniform.glslLocation, 1, v);
3930 }
3931 } else {
3932 packedArray.resize(elemCount * 2);
3933 qrhi_std140_to_packed(&packedArray.data()->f, 2, elemCount, src);
3934 f->glUniform2fv(uniform.glslLocation, elemCount, &packedArray.constData()->f);
3935 }
3936 }
3937 break;
3939 {
3940 const int elemCount = uniform.arrayDim;
3941 if (elemCount < 1) {
3942 const float *v = reinterpret_cast<const float *>(src);
3943 if (uniform.glslLocation <= QGles2UniformState::MAX_TRACKED_LOCATION) {
3944 QGles2UniformState &thisUniformState(uniformState[uniform.glslLocation]);
3945 if (thisUniformState.componentCount != 3
3946 || thisUniformState.v[0] != v[0]
3947 || thisUniformState.v[1] != v[1]
3948 || thisUniformState.v[2] != v[2])
3949 {
3950 thisUniformState.componentCount = 3;
3951 thisUniformState.v[0] = v[0];
3952 thisUniformState.v[1] = v[1];
3953 thisUniformState.v[2] = v[2];
3954 f->glUniform3fv(uniform.glslLocation, 1, v);
3955 }
3956 } else {
3957 f->glUniform3fv(uniform.glslLocation, 1, v);
3958 }
3959 } else {
3960 packedArray.resize(elemCount * 3);
3961 qrhi_std140_to_packed(&packedArray.data()->f, 3, elemCount, src);
3962 f->glUniform3fv(uniform.glslLocation, elemCount, &packedArray.constData()->f);
3963 }
3964 }
3965 break;
3967 {
3968 const int elemCount = uniform.arrayDim;
3969 if (elemCount < 1) {
3970 const float *v = reinterpret_cast<const float *>(src);
3971 if (uniform.glslLocation <= QGles2UniformState::MAX_TRACKED_LOCATION) {
3972 QGles2UniformState &thisUniformState(uniformState[uniform.glslLocation]);
3973 if (thisUniformState.componentCount != 4
3974 || thisUniformState.v[0] != v[0]
3975 || thisUniformState.v[1] != v[1]
3976 || thisUniformState.v[2] != v[2]
3977 || thisUniformState.v[3] != v[3])
3978 {
3979 thisUniformState.componentCount = 4;
3980 thisUniformState.v[0] = v[0];
3981 thisUniformState.v[1] = v[1];
3982 thisUniformState.v[2] = v[2];
3983 thisUniformState.v[3] = v[3];
3984 f->glUniform4fv(uniform.glslLocation, 1, v);
3985 }
3986 } else {
3987 f->glUniform4fv(uniform.glslLocation, 1, v);
3988 }
3989 } else {
3990 f->glUniform4fv(uniform.glslLocation, elemCount, reinterpret_cast<const float *>(src));
3991 }
3992 }
3993 break;
3995 f->glUniformMatrix2fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src));
3996 break;
3998 {
3999 const int elemCount = uniform.arrayDim;
4000 if (elemCount < 1) {
4001 // 4 floats per column (or row, if row-major)
4002 float mat[9];
4003 const float *srcMat = reinterpret_cast<const float *>(src);
4004 memcpy(mat, srcMat, 3 * sizeof(float));
4005 memcpy(mat + 3, srcMat + 4, 3 * sizeof(float));
4006 memcpy(mat + 6, srcMat + 8, 3 * sizeof(float));
4007 f->glUniformMatrix3fv(uniform.glslLocation, 1, GL_FALSE, mat);
4008 } else {
4009 packedArray.resize(elemCount * 9);
4010 qrhi_std140_to_packed(&packedArray.data()->f, 3, elemCount * 3, src);
4011 f->glUniformMatrix3fv(uniform.glslLocation, elemCount, GL_FALSE, &packedArray.constData()->f);
4012 }
4013 }
4014 break;
4016 f->glUniformMatrix4fv(uniform.glslLocation, qMax(1, uniform.arrayDim), GL_FALSE, reinterpret_cast<const float *>(src));
4017 break;
4019 {
4020 const int elemCount = uniform.arrayDim;
4021 if (elemCount < 1) {
4022 f->glUniform1i(uniform.glslLocation, *reinterpret_cast<const qint32 *>(src));
4023 } else {
4024 packedArray.resize(elemCount);
4025 qrhi_std140_to_packed(&packedArray.data()->i, 1, elemCount, src);
4026 f->glUniform1iv(uniform.glslLocation, elemCount, &packedArray.constData()->i);
4027 }
4028 }
4029 break;
4031 {
4032 const int elemCount = uniform.arrayDim;
4033 if (elemCount < 1) {
4034 f->glUniform2iv(uniform.glslLocation, 1, reinterpret_cast<const qint32 *>(src));
4035 } else {
4036 packedArray.resize(elemCount * 2);
4037 qrhi_std140_to_packed(&packedArray.data()->i, 2, elemCount, src);
4038 f->glUniform2iv(uniform.glslLocation, elemCount, &packedArray.constData()->i);
4039 }
4040 }
4041 break;
4043 {
4044 const int elemCount = uniform.arrayDim;
4045 if (elemCount < 1) {
4046 f->glUniform3iv(uniform.glslLocation, 1, reinterpret_cast<const qint32 *>(src));
4047 } else {
4048 packedArray.resize(elemCount * 3);
4049 qrhi_std140_to_packed(&packedArray.data()->i, 3, elemCount, src);
4050 f->glUniform3iv(uniform.glslLocation, elemCount, &packedArray.constData()->i);
4051 }
4052 }
4053 break;
4055 f->glUniform4iv(uniform.glslLocation, qMax(1, uniform.arrayDim), reinterpret_cast<const qint32 *>(src));
4056 break;
4058 f->glUniform1ui(uniform.glslLocation, *reinterpret_cast<const quint32 *>(src));
4059 break;
4061 f->glUniform2uiv(uniform.glslLocation, 1, reinterpret_cast<const quint32 *>(src));
4062 break;
4064 f->glUniform3uiv(uniform.glslLocation, 1, reinterpret_cast<const quint32 *>(src));
4065 break;
4067 f->glUniform4uiv(uniform.glslLocation, 1, reinterpret_cast<const quint32 *>(src));
4068 break;
4069 case QShaderDescription::Bool: // a glsl bool is 4 bytes, like (u)int
4070 f->glUniform1i(uniform.glslLocation, *reinterpret_cast<const qint32 *>(src));
4071 break;
4073 f->glUniform2iv(uniform.glslLocation, 1, reinterpret_cast<const qint32 *>(src));
4074 break;
4076 f->glUniform3iv(uniform.glslLocation, 1, reinterpret_cast<const qint32 *>(src));
4077 break;
4079 f->glUniform4iv(uniform.glslLocation, 1, reinterpret_cast<const qint32 *>(src));
4080 break;
4081 default:
4082 qWarning("Uniform with buffer binding %d, buffer offset %d has unsupported type %d",
4083 uniform.binding, uniform.offset, uniform.type);
4084 break;
4085 }
4086 }
4087 }
4088 }
4089 break;
4091 {
4092 const QGles2SamplerDescriptionVector &samplers(maybeGraphicsPs ? QRHI_RES(QGles2GraphicsPipeline, maybeGraphicsPs)->samplers
4093 : QRHI_RES(QGles2ComputePipeline, maybeComputePs)->samplers);
4094 void *ps;
4095 uint psGeneration;
4096 if (maybeGraphicsPs) {
4097 ps = maybeGraphicsPs;
4098 psGeneration = QRHI_RES(QGles2GraphicsPipeline, maybeGraphicsPs)->generation;
4099 } else {
4100 ps = maybeComputePs;
4101 psGeneration = QRHI_RES(QGles2ComputePipeline, maybeComputePs)->generation;
4102 }
4103 for (int elem = 0; elem < b->u.stex.count; ++elem) {
4104 QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex);
4105 QGles2Sampler *samplerD = QRHI_RES(QGles2Sampler, b->u.stex.texSamplers[elem].sampler);
4106 for (const QGles2SamplerDescription &shaderSampler : samplers) {
4107 if (shaderSampler.combinedBinding == b->binding) {
4108 const int loc = shaderSampler.glslLocation + elem;
4109 bindCombinedSampler(cbD, texD, samplerD, ps, psGeneration, loc, &texUnit, &activeTexUnitAltered);
4110 break;
4111 }
4112 }
4113 }
4114 }
4115 break;
4117 for (int elem = 0; elem < b->u.stex.count; ++elem) {
4118 QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex);
4119 separateTextureBindings.append({ texD, b->binding, elem });
4120 }
4121 break;
4123 {
4124 QGles2Sampler *samplerD = QRHI_RES(QGles2Sampler, b->u.stex.texSamplers[0].sampler);
4125 separateSamplerBindings.append({ samplerD, b->binding });
4126 }
4127 break;
4131 {
4132 QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.simage.tex);
4134 const bool layered = texD->m_flags.testFlag(QRhiTexture::CubeMap);
4138 else if (b->type == QRhiShaderResourceBinding::ImageStore)
4140 f->glBindImageTexture(GLuint(b->binding), texD->texture,
4141 b->u.simage.level, layered, 0,
4142 access, texD->glsizedintformat);
4143 }
4144 break;
4148 {
4149 QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b->u.sbuf.buf);
4151 if (b->u.sbuf.offset == 0 && b->u.sbuf.maybeSize == 0)
4152 f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, GLuint(b->binding), bufD->buffer);
4153 else
4154 f->glBindBufferRange(GL_SHADER_STORAGE_BUFFER, GLuint(b->binding), bufD->buffer,
4155 b->u.sbuf.offset, b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : bufD->m_size);
4156 }
4157 break;
4158 default:
4159 Q_UNREACHABLE();
4160 break;
4161 }
4162 }
4163
4164 if (!separateTextureBindings.isEmpty() || !separateSamplerBindings.isEmpty()) {
4165 const QGles2SamplerDescriptionVector &samplers(maybeGraphicsPs ? QRHI_RES(QGles2GraphicsPipeline, maybeGraphicsPs)->samplers
4166 : QRHI_RES(QGles2ComputePipeline, maybeComputePs)->samplers);
4167 void *ps;
4168 uint psGeneration;
4169 if (maybeGraphicsPs) {
4170 ps = maybeGraphicsPs;
4171 psGeneration = QRHI_RES(QGles2GraphicsPipeline, maybeGraphicsPs)->generation;
4172 } else {
4173 ps = maybeComputePs;
4174 psGeneration = QRHI_RES(QGles2ComputePipeline, maybeComputePs)->generation;
4175 }
4176 for (const QGles2SamplerDescription &shaderSampler : samplers) {
4177 if (shaderSampler.combinedBinding >= 0)
4178 continue;
4179 for (const SeparateSampler &sepSampler : separateSamplerBindings) {
4180 if (sepSampler.binding != shaderSampler.sbinding)
4181 continue;
4182 for (const SeparateTexture &sepTex : separateTextureBindings) {
4183 if (sepTex.binding != shaderSampler.tbinding)
4184 continue;
4185 const int loc = shaderSampler.glslLocation + sepTex.elem;
4186 bindCombinedSampler(cbD, sepTex.texture, sepSampler.sampler, ps, psGeneration,
4187 loc, &texUnit, &activeTexUnitAltered);
4188 }
4189 }
4190 }
4191 }
4192
4193 if (activeTexUnitAltered)
4194 f->glActiveTexture(GL_TEXTURE0);
4195}
4196
4198{
4200
4201 enqueueResourceUpdates(cb, resourceUpdates);
4202}
4203
4205 bool *wantsColorClear, bool *wantsDsClear)
4206{
4207 QGles2RenderTargetData *rtD = nullptr;
4209
4210 QGles2CommandBuffer::Command &fbCmd(cbD->commands.get());
4212
4213 static const bool doClearBuffers = qEnvironmentVariableIntValue("QT_GL_NO_CLEAR_BUFFERS") == 0;
4214 static const bool doClearColorBuffer = qEnvironmentVariableIntValue("QT_GL_NO_CLEAR_COLOR_BUFFER") == 0;
4215
4216 switch (rt->resourceType()) {
4219 if (wantsColorClear)
4220 *wantsColorClear = doClearBuffers && doClearColorBuffer;
4221 if (wantsDsClear)
4222 *wantsDsClear = doClearBuffers;
4223 fbCmd.args.bindFramebuffer.fbo = 0;
4225 fbCmd.args.bindFramebuffer.stereo = rtD->stereoTarget.has_value();
4226 if (fbCmd.args.bindFramebuffer.stereo)
4227 fbCmd.args.bindFramebuffer.stereoTarget = rtD->stereoTarget.value();
4228 break;
4230 {
4232 rtD = &rtTex->d;
4233 if (wantsColorClear)
4234 *wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
4235 if (wantsDsClear)
4236 *wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
4237 fbCmd.args.bindFramebuffer.fbo = rtTex->framebuffer;
4239 fbCmd.args.bindFramebuffer.stereo = false;
4240
4241 for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
4242 it != itEnd; ++it)
4243 {
4244 const QRhiColorAttachment &colorAtt(*it);
4245 QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAtt.texture());
4246 QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
4247 if (texD && cbD->passNeedsResourceTracking) {
4248 trackedRegisterTexture(&passResTracker, texD,
4251 }
4252 if (resolveTexD && cbD->passNeedsResourceTracking) {
4253 trackedRegisterTexture(&passResTracker, resolveTexD,
4256 }
4257 // renderbuffers cannot be written in shaders (no image store) so
4258 // they do not matter here
4259 }
4260 if (rtTex->m_desc.depthTexture() && cbD->passNeedsResourceTracking) {
4264 }
4265 }
4266 break;
4267 default:
4268 Q_UNREACHABLE();
4269 break;
4270 }
4271
4273
4274 return rtD;
4275}
4276
4278{
4281 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
4284}
4285
4287 QRhiRenderTarget *rt,
4288 const QColor &colorClearValue,
4289 const QRhiDepthStencilClearValue &depthStencilClearValue,
4290 QRhiResourceUpdateBatch *resourceUpdates,
4291 QRhiCommandBuffer::BeginPassFlags flags)
4292{
4295
4296 if (resourceUpdates)
4297 enqueueResourceUpdates(cb, resourceUpdates);
4298
4299 // Get a new resource tracker. Then add a command that will generate
4300 // glMemoryBarrier() calls based on that tracker when submitted.
4302
4305 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QGles2Texture, QGles2RenderBuffer>(rtTex->description(), rtTex->d.currentResIdList))
4306 rtTex->create();
4307 }
4308
4309 bool wantsColorClear, wantsDsClear;
4310 QGles2RenderTargetData *rtD = enqueueBindFramebuffer(rt, cbD, &wantsColorClear, &wantsDsClear);
4311
4312 QGles2CommandBuffer::Command &clearCmd(cbD->commands.get());
4314 clearCmd.args.clear.mask = 0;
4315 if (rtD->colorAttCount && wantsColorClear)
4316 clearCmd.args.clear.mask |= GL_COLOR_BUFFER_BIT;
4317 if (rtD->dsAttCount && wantsDsClear)
4318 clearCmd.args.clear.mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
4319 clearCmd.args.clear.c[0] = float(colorClearValue.redF());
4320 clearCmd.args.clear.c[1] = float(colorClearValue.greenF());
4321 clearCmd.args.clear.c[2] = float(colorClearValue.blueF());
4322 clearCmd.args.clear.c[3] = float(colorClearValue.alphaF());
4323 clearCmd.args.clear.d = depthStencilClearValue.depthClearValue();
4324 clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
4325
4328 cbD->currentTarget = rt;
4329
4330 cbD->resetCachedState();
4331}
4332
4334{
4337
4340 for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
4341 it != itEnd; ++it)
4342 {
4343 const QRhiColorAttachment &colorAtt(*it);
4344 if (!colorAtt.resolveTexture())
4345 continue;
4346
4347 QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
4348 const QSize size = resolveTexD->pixelSize();
4349 if (colorAtt.renderBuffer()) {
4351 if (rbD->pixelSize() != size) {
4352 qWarning("Resolve source (%dx%d) and target (%dx%d) size does not match",
4353 rbD->pixelSize().width(), rbD->pixelSize().height(), size.width(), size.height());
4354 }
4355 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
4358 cmd.args.blitFromRenderbuffer.w = size.width();
4359 cmd.args.blitFromRenderbuffer.h = size.height();
4360 if (resolveTexD->m_flags.testFlag(QRhiTexture::CubeMap))
4362 else
4363 cmd.args.blitFromRenderbuffer.target = resolveTexD->target;
4364 cmd.args.blitFromRenderbuffer.dstTexture = resolveTexD->texture;
4366 const bool hasZ = resolveTexD->m_flags.testFlag(QRhiTexture::ThreeDimensional)
4367 || resolveTexD->m_flags.testFlag(QRhiTexture::TextureArray);
4368 cmd.args.blitFromRenderbuffer.dstLayer = hasZ ? colorAtt.resolveLayer() : 0;
4369 } else {
4370 Q_ASSERT(colorAtt.texture());
4371 QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAtt.texture());
4372 if (texD->pixelSize() != size) {
4373 qWarning("Resolve source (%dx%d) and target (%dx%d) size does not match",
4374 texD->pixelSize().width(), texD->pixelSize().height(), size.width(), size.height());
4375 }
4376 const int resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
4377 for (int resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
4378 const int srcLayer = colorAtt.layer() + resolveIdx;
4379 const int dstLayer = colorAtt.resolveLayer() + resolveIdx;
4380 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
4382 if (texD->m_flags.testFlag(QRhiTexture::CubeMap))
4384 else
4387 cmd.args.blitFromTexture.srcLevel = colorAtt.level();
4389 if (texD->m_flags.testFlag(QRhiTexture::ThreeDimensional) || texD->m_flags.testFlag(QRhiTexture::TextureArray))
4390 cmd.args.blitFromTexture.srcLayer = srcLayer;
4391 cmd.args.blitFromTexture.w = size.width();
4392 cmd.args.blitFromTexture.h = size.height();
4393 if (resolveTexD->m_flags.testFlag(QRhiTexture::CubeMap))
4395 else
4396 cmd.args.blitFromTexture.dstTarget = resolveTexD->target;
4397 cmd.args.blitFromTexture.dstTexture = resolveTexD->texture;
4398 cmd.args.blitFromTexture.dstLevel = colorAtt.resolveLevel();
4400 if (resolveTexD->m_flags.testFlag(QRhiTexture::ThreeDimensional) || resolveTexD->m_flags.testFlag(QRhiTexture::TextureArray))
4401 cmd.args.blitFromTexture.dstLayer = dstLayer;
4402 }
4403 }
4404 }
4405 }
4406
4408 cbD->currentTarget = nullptr;
4409
4410 if (resourceUpdates)
4411 enqueueResourceUpdates(cb, resourceUpdates);
4412}
4413
4415 QRhiResourceUpdateBatch *resourceUpdates,
4416 QRhiCommandBuffer::BeginPassFlags)
4417{
4420
4421 if (resourceUpdates)
4422 enqueueResourceUpdates(cb, resourceUpdates);
4423
4425
4427
4428 cbD->resetCachedState();
4429}
4430
4432{
4435
4437
4438 if (resourceUpdates)
4439 enqueueResourceUpdates(cb, resourceUpdates);
4440}
4441
4443{
4447 const bool pipelineChanged = cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation;
4448
4449 if (pipelineChanged) {
4450 cbD->currentGraphicsPipeline = nullptr;
4451 cbD->currentComputePipeline = ps;
4453
4454 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
4456 cmd.args.bindComputePipeline.ps = ps;
4457 }
4458}
4459
4460template<typename T>
4461inline void qrhigl_accumulateComputeResource(T *writtenResources, QRhiResource *resource,
4463 int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
4464{
4465 int access = 0;
4466 if (bindingType == loadTypeVal) {
4468 } else {
4470 if (bindingType == loadStoreTypeVal)
4472 }
4473 auto it = writtenResources->find(resource);
4474 if (it != writtenResources->end())
4475 it->first |= access;
4476 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
4477 writtenResources->insert(resource, { access, true });
4478}
4479
4481{
4484
4485 if (cbD->currentComputeSrb) {
4486 GLbitfield barriers = 0;
4487
4488 // The key in the writtenResources map indicates that the resource was
4489 // written in a previous dispatch, whereas the value accumulates the
4490 // access mask in the current one.
4491 for (auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
4492 accessAndIsNewFlag = { 0, false };
4493
4495 const int bindingCount = srbD->m_bindings.size();
4496 for (int i = 0; i < bindingCount; ++i) {
4498 switch (b->type) {
4503 b->u.simage.tex,
4504 b->type,
4508 break;
4513 b->u.sbuf.buf,
4514 b->type,
4518 break;
4519 default:
4520 break;
4521 }
4522 }
4523
4525 const int accessInThisDispatch = it->first;
4526 const bool isNewInThisDispatch = it->second;
4527 if (accessInThisDispatch && !isNewInThisDispatch) {
4528 if (it.key()->resourceType() == QRhiResource::Texture)
4530 else
4532 }
4533 // Anything that was previously written, but is only read now, can be
4534 // removed from the written list (because that previous write got a
4535 // corresponding barrier now).
4536 if (accessInThisDispatch == QGles2CommandBuffer::ComputePassState::Read)
4538 else
4539 ++it;
4540 }
4541
4542 if (barriers) {
4543 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
4545 cmd.args.barrier.barriers = barriers;
4546 }
4547 }
4548
4549 QGles2CommandBuffer::Command &cmd(cbD->commands.get());
4551 cmd.args.dispatch.x = GLuint(x);
4552 cmd.args.dispatch.y = GLuint(y);
4553 cmd.args.dispatch.z = GLuint(z);
4554}
4555
4557{
4558 switch (type) {
4560 return GL_VERTEX_SHADER;
4566 return GL_GEOMETRY_SHADER;
4568 return GL_FRAGMENT_SHADER;
4570 return GL_COMPUTE_SHADER;
4571 default:
4572 Q_UNREACHABLE_RETURN(GL_VERTEX_SHADER);
4573 }
4574}
4575
4577{
4578 const QShader bakedShader = shaderStage.shader();
4579 QList<int> versionsToTry;
4581 if (caps.gles) {
4582 if (caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2)) {
4583 versionsToTry << 320 << 310 << 300 << 100;
4584 } else if (caps.ctxMajor == 3 && caps.ctxMinor == 1) {
4585 versionsToTry << 310 << 300 << 100;
4586 } else if (caps.ctxMajor == 3 && caps.ctxMinor == 0) {
4587 versionsToTry << 300 << 100;
4588 } else {
4589 versionsToTry << 100;
4590 }
4591 for (int v : versionsToTry) {
4593 source = bakedShader.shader({ QShader::GlslShader, ver, shaderStage.shaderVariant() }).shader();
4594 if (!source.isEmpty()) {
4595 if (shaderVersion)
4596 *shaderVersion = ver;
4597 break;
4598 }
4599 }
4600 } else {
4601 if (caps.ctxMajor > 4 || (caps.ctxMajor == 4 && caps.ctxMinor >= 6)) {
4602 versionsToTry << 460 << 450 << 440 << 430 << 420 << 410 << 400 << 330 << 150 << 140 << 130;
4603 } else if (caps.ctxMajor == 4 && caps.ctxMinor == 5) {
4604 versionsToTry << 450 << 440 << 430 << 420 << 410 << 400 << 330 << 150 << 140 << 130;
4605 } else if (caps.ctxMajor == 4 && caps.ctxMinor == 4) {
4606 versionsToTry << 440 << 430 << 420 << 410 << 400 << 330 << 150 << 140 << 130;
4607 } else if (caps.ctxMajor == 4 && caps.ctxMinor == 3) {
4608 versionsToTry << 430 << 420 << 410 << 400 << 330 << 150 << 140 << 130;
4609 } else if (caps.ctxMajor == 4 && caps.ctxMinor == 2) {
4610 versionsToTry << 420 << 410 << 400 << 330 << 150 << 140 << 130;
4611 } else if (caps.ctxMajor == 4 && caps.ctxMinor == 1) {
4612 versionsToTry << 410 << 400 << 330 << 150 << 140 << 130;
4613 } else if (caps.ctxMajor == 4 && caps.ctxMinor == 0) {
4614 versionsToTry << 400 << 330 << 150 << 140 << 130;
4615 } else if (caps.ctxMajor == 3 && caps.ctxMinor == 3) {
4616 versionsToTry << 330 << 150 << 140 << 130;
4617 } else if (caps.ctxMajor == 3 && caps.ctxMinor == 2) {
4618 versionsToTry << 150 << 140 << 130;
4619 } else if (caps.ctxMajor == 3 && caps.ctxMinor == 1) {
4620 versionsToTry << 140 << 130;
4621 } else if (caps.ctxMajor == 3 && caps.ctxMinor == 0) {
4622 versionsToTry << 130;
4623 }
4624 if (!caps.coreProfile)
4625 versionsToTry << 120;
4626 for (int v : versionsToTry) {
4627 source = bakedShader.shader({ QShader::GlslShader, v, shaderStage.shaderVariant() }).shader();
4628 if (!source.isEmpty()) {
4629 if (shaderVersion)
4630 *shaderVersion = v;
4631 break;
4632 }
4633 }
4634 }
4635 if (source.isEmpty()) {
4636 qWarning() << "No GLSL shader code found (versions tried: " << versionsToTry
4637 << ") in baked shader" << bakedShader;
4638 }
4639 return source;
4640}
4641
4643{
4644 const QByteArray source = shaderSource(shaderStage, shaderVersion);
4645 if (source.isEmpty())
4646 return false;
4647
4648 GLuint shader;
4649 auto cacheIt = m_shaderCache.constFind(shaderStage);
4650 if (cacheIt != m_shaderCache.constEnd()) {
4651 shader = *cacheIt;
4652 } else {
4653 shader = f->glCreateShader(toGlShaderType(shaderStage.type()));
4654 const char *srcStr = source.constData();
4655 const GLint srcLength = source.size();
4656 f->glShaderSource(shader, 1, &srcStr, &srcLength);
4657 f->glCompileShader(shader);
4658 GLint compiled = 0;
4659 f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
4660 if (!compiled) {
4661 GLint infoLogLength = 0;
4662 f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
4663 QByteArray log;
4664 if (infoLogLength > 1) {
4665 GLsizei length = 0;
4666 log.resize(infoLogLength);
4667 f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data());
4668 }
4669 qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData());
4670 return false;
4671 }
4673 // Use the simplest strategy: too many cached shaders -> drop them all.
4674 for (uint shader : m_shaderCache)
4675 f->glDeleteShader(shader); // does not actually get released yet when attached to a not-yet-released program
4677 }
4678 m_shaderCache.insert(shaderStage, shader);
4679 }
4680
4681 f->glAttachShader(program, shader);
4682
4683 return true;
4684}
4685
4687{
4688 f->glLinkProgram(program);
4689 GLint linked = 0;
4690 f->glGetProgramiv(program, GL_LINK_STATUS, &linked);
4691 if (!linked) {
4692 GLint infoLogLength = 0;
4693 f->glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
4694 QByteArray log;
4695 if (infoLogLength > 1) {
4696 GLsizei length = 0;
4697 log.resize(infoLogLength);
4698 f->glGetProgramInfoLog(program, infoLogLength, &length, log.data());
4699 }
4700 qWarning("Failed to link shader program: %s", log.constData());
4701 return false;
4702 }
4703 return true;
4704}
4705
4707 const QByteArray &namePrefix,
4708 int binding,
4709 int baseOffset,
4711 QDuplicateTracker<int, 256> *activeUniformLocations,
4713{
4714 if (var.type == QShaderDescription::Struct) {
4715 qWarning("Nested structs are not supported at the moment. '%s' ignored.",
4716 var.name.constData());
4717 return;
4718 }
4720 uniform.type = var.type;
4721 const QByteArray name = namePrefix + var.name;
4722 // Here we expect that the OpenGL implementation has proper active uniform
4723 // handling, meaning that a uniform that is declared but not accessed
4724 // elsewhere in the code is reported as -1 when querying the location. If
4725 // that is not the case, it won't break anything, but we'll generate
4726 // unnecessary glUniform* calls then.
4727 uniform.glslLocation = f->glGetUniformLocation(program, name.constData());
4728 if (uniform.glslLocation >= 0 && !activeUniformLocations->hasSeen(uniform.glslLocation)) {
4729 if (var.arrayDims.size() > 1) {
4730 qWarning("Array '%s' has more than one dimension. This is not supported.",
4731 var.name.constData());
4732 return;
4733 }
4734 uniform.binding = binding;
4735 uniform.offset = uint(baseOffset + var.offset);
4736 uniform.size = var.size;
4737 uniform.arrayDim = var.arrayDims.isEmpty() ? 0 : var.arrayDims.first();
4738 dst->append(uniform);
4739 }
4740}
4741
4744 QDuplicateTracker<int, 256> *activeUniformLocations,
4746{
4747 QByteArray prefix = ub.structName + '.';
4748 for (const QShaderDescription::BlockVariable &blockMember : ub.members) {
4749 if (blockMember.type == QShaderDescription::Struct) {
4750 QByteArray structPrefix = prefix + blockMember.name;
4751
4752 const int baseOffset = blockMember.offset;
4753 if (blockMember.arrayDims.isEmpty()) {
4754 for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
4755 registerUniformIfActive(structMember, structPrefix + ".", ub.binding,
4756 baseOffset, program, activeUniformLocations, dst);
4757 } else {
4758 if (blockMember.arrayDims.size() > 1) {
4759 qWarning("Array of struct '%s' has more than one dimension. Only the first "
4760 "dimension is used.",
4761 blockMember.name.constData());
4762 }
4763 const int dim = blockMember.arrayDims.first();
4764 const int elemSize = blockMember.size / dim;
4765 int elemOffset = baseOffset;
4766 for (int di = 0; di < dim; ++di) {
4767 const QByteArray arrayPrefix = structPrefix + '[' + QByteArray::number(di) + ']' + '.';
4768 for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
4769 registerUniformIfActive(structMember, arrayPrefix, ub.binding, elemOffset, program, activeUniformLocations, dst);
4770 elemOffset += elemSize;
4771 }
4772 }
4773 } else {
4774 registerUniformIfActive(blockMember, prefix, ub.binding, 0, program, activeUniformLocations, dst);
4775 }
4776 }
4777}
4778
4782{
4784 sampler.glslLocation = f->glGetUniformLocation(program, v.name.constData());
4785 if (sampler.glslLocation >= 0) {
4786 sampler.combinedBinding = v.binding;
4787 sampler.tbinding = -1;
4788 sampler.sbinding = -1;
4789 dst->append(sampler);
4790 }
4791}
4792
4796{
4798 sampler.glslLocation = f->glGetUniformLocation(program, mapping.combinedSamplerName.constData());
4799 if (sampler.glslLocation >= 0) {
4800 sampler.combinedBinding = -1;
4801 sampler.tbinding = mapping.textureBinding;
4802 sampler.sbinding = mapping.samplerBinding;
4803 dst->append(sampler);
4804 }
4805}
4806
4808{
4809 if (!vsDesc.isValid() || !fsDesc.isValid())
4810 return;
4811
4812 // Print a warning if the fragment shader input for a given location uses a
4813 // name that does not match the vertex shader output at the same location.
4814 // This is not an error with any other API and not with GLSL >= 330 either,
4815 // but matters for older GLSL code that has no location qualifiers.
4816 for (const QShaderDescription::InOutVariable &outVar : vsDesc.outputVariables()) {
4817 for (const QShaderDescription::InOutVariable &inVar : fsDesc.inputVariables()) {
4818 if (inVar.location == outVar.location) {
4819 if (inVar.name != outVar.name) {
4820 qWarning("Vertex output name '%s' does not match fragment input '%s'. "
4821 "This should be avoided because it causes problems with older GLSL versions.",
4822 outVar.name.constData(), inVar.name.constData());
4823 }
4824 break;
4825 }
4826 }
4827 }
4828}
4829
4831{
4833 return checker.get(ctx)->isSupported();
4834}
4835
4837
4839{
4840 switch (type) {
4842 return QShader::VertexStage;
4852 return QShader::ComputeStage;
4853 default:
4854 Q_UNREACHABLE_RETURN(QShader::VertexStage);
4855 }
4856}
4857
4859 int stageCount,
4862 QByteArray *cacheKey)
4863{
4864 Q_ASSERT(cacheKey);
4865
4866 // the traditional QOpenGL disk cache since Qt 5.9
4867 const bool legacyDiskCacheEnabled = isProgramBinaryDiskCacheEnabled();
4868
4869 // QRhi's own (set)PipelineCacheData()
4870 const bool pipelineCacheEnabled = caps.programBinary && !m_pipelineCache.isEmpty();
4871
4872 // calculating the cache key based on the source code is common for both types of caches
4873 if (legacyDiskCacheEnabled || pipelineCacheEnabled) {
4875 for (int i = 0; i < stageCount; ++i) {
4876 const QRhiShaderStage &stage(stages[i]);
4877 QByteArray source = shaderSource(stage, nullptr);
4878 if (source.isEmpty())
4880
4881 if (stage.type() == QRhiShaderStage::Vertex) {
4882 // Now add something to the key that indicates the vertex input locations.
4883 // A GLSL shader lower than 330 (150, 140, ...) will not have location
4884 // qualifiers. This means that the shader source code is the same
4885 // regardless of what locations inputVars contains. This becomes a problem
4886 // because we'll glBindAttribLocation the shader based on inputVars, but
4887 // that's only when compiling/linking when there was no cache hit. Picking
4888 // from the cache afterwards should take the input locations into account
4889 // since if inputVars has now different locations for the attributes, then
4890 // it is not ok to reuse a program binary that used different attribute
4891 // locations. For a lot of clients this would not be an issue since they
4892 // typically hardcode and use the same vertex locations on every run. Some
4893 // systems that dynamically generate shaders may end up with a non-stable
4894 // order (and so location numbers), however. This is sub-optimal because
4895 // it makes caching inefficient, and said clients should be fixed, but in
4896 // any case this should not break rendering. Hence including the locations
4897 // in the cache key.
4898 QMap<QByteArray, int> inputLocations; // sorted by key when iterating
4899 for (const QShaderDescription::InOutVariable &var : inputVars)
4900 inputLocations.insert(var.name, var.location);
4901 source += QByteArrayLiteral("\n // "); // just to be nice; treated as an arbitrary string regardless
4902 for (auto it = inputLocations.cbegin(), end = inputLocations.cend(); it != end; ++it) {
4903 source += it.key();
4904 source += QByteArray::number(it.value());
4905 }
4906 source += QByteArrayLiteral("\n");
4907 }
4908
4910 }
4911
4912 *cacheKey = binaryProgram.cacheKey();
4913
4914 // Try our pipeline cache simulation first, if it got seeded with
4915 // setPipelineCacheData and there's a hit, then no need to go to the
4916 // filesystem at all.
4917 if (pipelineCacheEnabled) {
4918 auto it = m_pipelineCache.constFind(*cacheKey);
4919 if (it != m_pipelineCache.constEnd()) {
4920 GLenum err;
4921 for ( ; ; ) {
4922 err = f->glGetError();
4923 if (err == GL_NO_ERROR || err == GL_CONTEXT_LOST)
4924 break;
4925 }
4926 f->glProgramBinary(program, it->format, it->data.constData(), it->data.size());
4927 err = f->glGetError();
4928 if (err == GL_NO_ERROR) {
4929 GLint linkStatus = 0;
4930 f->glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
4931 if (linkStatus == GL_TRUE)
4933 }
4934 }
4935 }
4936
4937 if (legacyDiskCacheEnabled && qrhi_programBinaryCache()->load(*cacheKey, program)) {
4938 // use the logging category QOpenGLShaderProgram would
4939 qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
4940 program, cacheKey->constData());
4942 }
4943 }
4944
4946}
4947
4949{
4950 // This is only for the traditional QOpenGL disk cache since Qt 5.9.
4951
4953 // use the logging category QOpenGLShaderProgram would
4954 qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s",
4955 program, cacheKey.constData());
4956 qrhi_programBinaryCache()->save(cacheKey, program);
4957 }
4958}
4959
4961{
4962 // This handles our own simulated "pipeline cache". (specific to QRhi, not
4963 // shared with legacy QOpenGL* stuff)
4964
4965 if (caps.programBinary && (force || !m_pipelineCache.contains(cacheKey))) {
4966 GLint blobSize = 0;
4967 f->glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &blobSize);
4968 QByteArray blob(blobSize, Qt::Uninitialized);
4969 GLint outSize = 0;
4970 GLenum binaryFormat = 0;
4971 f->glGetProgramBinary(program, blobSize, &outSize, &binaryFormat, blob.data());
4972 if (blobSize == outSize)
4973 m_pipelineCache.insert(cacheKey, { binaryFormat, blob });
4974 }
4975}
4976
4978 : QRhiBuffer(rhi, type, usage, size)
4979{
4980}
4981
4983{
4984 destroy();
4985}
4986
4988{
4989 data.clear();
4990 if (!buffer)
4991 return;
4992
4995
4996 e.buffer.buffer = buffer;
4997 buffer = 0;
4998
5000 if (rhiD) {
5001 rhiD->releaseQueue.append(e);
5002 rhiD->unregisterResource(this);
5003 }
5004}
5005
5007{
5008 if (buffer)
5009 destroy();
5010
5012
5013 nonZeroSize = m_size <= 0 ? 256 : m_size;
5014
5015 if (m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
5016 if (int(m_usage) != QRhiBuffer::UniformBuffer) {
5017 qWarning("Uniform buffer: multiple usages specified, this is not supported by the OpenGL backend");
5018 return false;
5019 }
5020 data.resize(nonZeroSize);
5021 return true;
5022 }
5023
5024 if (!rhiD->ensureContext())
5025 return false;
5026
5028 if (m_usage.testFlag(QRhiBuffer::IndexBuffer))
5030 else if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
5032
5033 rhiD->f->glGenBuffers(1, &buffer);
5034 rhiD->f->glBindBuffer(targetForDataOps, buffer);
5035 rhiD->f->glBufferData(targetForDataOps, nonZeroSize, nullptr, m_type == Dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
5036
5038
5039 rhiD->registerResource(this);
5040 return true;
5041}
5042
5044{
5045 if (m_usage.testFlag(QRhiBuffer::UniformBuffer))
5046 return { {}, 0 };
5047
5048 return { { &buffer }, 1 };
5049}
5050
5052{
5054 if (!m_usage.testFlag(UniformBuffer)) {
5056 rhiD->f->glBindBuffer(targetForDataOps, buffer);
5057 if (rhiD->caps.properMapBuffer) {
5058 return static_cast<char *>(rhiD->f->glMapBufferRange(targetForDataOps, 0, nonZeroSize,
5060 } else {
5061 // Need some storage for the data, use the otherwise unused 'data' member.
5062 if (data.isEmpty())
5063 data.resize(nonZeroSize);
5064 }
5065 }
5066 return data.data();
5067}
5068
5070{
5071 if (!m_usage.testFlag(UniformBuffer)) {
5073 if (rhiD->caps.properMapBuffer)
5074 rhiD->f->glUnmapBuffer(targetForDataOps);
5075 else
5076 rhiD->f->glBufferSubData(targetForDataOps, 0, nonZeroSize, data.data());
5077 }
5078}
5079
5081 int sampleCount, QRhiRenderBuffer::Flags flags,
5082 QRhiTexture::Format backingFormatHint)
5083 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
5084{
5085}
5086
5088{
5089 destroy();
5090}
5091
5093{
5094 if (!renderbuffer)
5095 return;
5096
5099
5100 e.renderbuffer.renderbuffer = renderbuffer;
5101 e.renderbuffer.renderbuffer2 = stencilRenderbuffer;
5102
5103 renderbuffer = 0;
5105
5107 if (rhiD) {
5108 if (owns)
5109 rhiD->releaseQueue.append(e);
5110 rhiD->unregisterResource(this);
5111 }
5112}
5113
5115{
5116 if (renderbuffer)
5117 destroy();
5118
5120 samples = rhiD->effectiveSampleCount(m_sampleCount);
5121
5122 if (m_flags.testFlag(UsedWithSwapChainOnly)) {
5123 if (m_type == DepthStencil)
5124 return true;
5125
5126 qWarning("RenderBuffer: UsedWithSwapChainOnly is meaningless in combination with Color");
5127 }
5128
5129 if (!rhiD->ensureContext())
5130 return false;
5131
5132 rhiD->f->glGenRenderbuffers(1, &renderbuffer);
5133 rhiD->f->glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
5134
5135 const QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
5136
5137 switch (m_type) {
5139 if (rhiD->caps.msaaRenderBuffer && samples > 1) {
5140 rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8,
5141 size.width(), size.height());
5143 } else if (rhiD->caps.packedDepthStencil || rhiD->caps.needsDepthStencilCombinedAttach) {
5144 const GLenum storage = rhiD->caps.needsDepthStencilCombinedAttach ? GL_DEPTH_STENCIL : GL_DEPTH24_STENCIL8;
5145 rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, storage,
5146 size.width(), size.height());
5148 } else {
5149 GLenum depthStorage = GL_DEPTH_COMPONENT;
5150 if (rhiD->caps.gles) {
5151 if (rhiD->caps.depth24)
5152 depthStorage = GL_DEPTH_COMPONENT24;
5153 else
5154 depthStorage = GL_DEPTH_COMPONENT16; // plain ES 2.0 only has this
5155 }
5156 const GLenum stencilStorage = rhiD->caps.gles ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX;
5157 rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, depthStorage,
5158 size.width(), size.height());
5159 rhiD->f->glGenRenderbuffers(1, &stencilRenderbuffer);
5160 rhiD->f->glBindRenderbuffer(GL_RENDERBUFFER, stencilRenderbuffer);
5161 rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, stencilStorage,
5162 size.width(), size.height());
5163 }
5164 break;
5166 {
5167 GLenum internalFormat = GL_RGBA4; // ES 2.0
5168 if (rhiD->caps.rgba8Format) {
5171 GLenum glintformat, glformat, gltype;
5172 // only care about the sized internal format, the rest is not used here
5174 &glintformat, &internalFormat, &glformat, &gltype);
5175 }
5176 }
5177 if (rhiD->caps.msaaRenderBuffer && samples > 1) {
5178 rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalFormat,
5179 size.width(), size.height());
5180 } else {
5181 rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, internalFormat,
5182 size.width(), size.height());
5183 }
5184 }
5185 break;
5186 default:
5187 Q_UNREACHABLE();
5188 break;
5189 }
5190
5191 owns = true;
5192 generation += 1;
5193 rhiD->registerResource(this);
5194 return true;
5195}
5196
5198{
5199 if (!src.object)
5200 return false;
5201
5202 if (renderbuffer)
5203 destroy();
5204
5206 samples = rhiD->effectiveSampleCount(m_sampleCount);
5207
5208 if (m_flags.testFlag(UsedWithSwapChainOnly))
5209 qWarning("RenderBuffer: UsedWithSwapChainOnly is meaningless when importing an existing native object");
5210
5211 if (!rhiD->ensureContext())
5212 return false;
5213
5214 renderbuffer = src.object;
5215
5216 owns = false;
5217 generation += 1;
5218 rhiD->registerResource(this);
5219 return true;
5220}
5221
5223{
5225 return m_backingFormatHint;
5226 else
5228}
5229
5231 int arraySize, int sampleCount, Flags flags)
5232 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
5233{
5234}
5235
5237{
5238 destroy();
5239}
5240
5242{
5243 if (!texture)
5244 return;
5245
5248
5249 e.texture.texture = texture;
5250
5251 texture = 0;
5252 specified = false;
5253 zeroInitialized = false;
5254
5256 if (rhiD) {
5257 if (owns)
5258 rhiD->releaseQueue.append(e);
5259 rhiD->unregisterResource(this);
5260 }
5261}
5262
5264{
5265 if (texture)
5266 destroy();
5267
5269 if (!rhiD->ensureContext())
5270 return false;
5271
5272 const bool isCube = m_flags.testFlag(CubeMap);
5273 const bool isArray = m_flags.testFlag(QRhiTexture::TextureArray);
5274 const bool is3D = m_flags.testFlag(ThreeDimensional);
5275 const bool hasMipMaps = m_flags.testFlag(MipMapped);
5276 const bool isCompressed = rhiD->isCompressedFormat(m_format);
5277 const bool is1D = m_flags.testFlag(OneDimensional);
5278
5279 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
5280 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
5281
5282 if (is3D && !rhiD->caps.texture3D) {
5283 qWarning("3D textures are not supported");
5284 return false;
5285 }
5286 if (isCube && is3D) {
5287 qWarning("Texture cannot be both cube and 3D");
5288 return false;
5289 }
5290 if (isArray && is3D) {
5291 qWarning("Texture cannot be both array and 3D");
5292 return false;
5293 }
5294 if (is1D && !rhiD->caps.texture1D) {
5295 qWarning("1D textures are not supported");
5296 return false;
5297 }
5298 if (is1D && is3D) {
5299 qWarning("Texture cannot be both 1D and 3D");
5300 return false;
5301 }
5302 if (is1D && isCube) {
5303 qWarning("Texture cannot be both 1D and cube");
5304 return false;
5305 }
5306
5307 if (m_depth > 1 && !is3D) {
5308 qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
5309 return false;
5310 }
5311 if (m_arraySize > 0 && !isArray) {
5312 qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
5313 return false;
5314 }
5315 if (m_arraySize < 1 && isArray) {
5316 qWarning("Texture is an array but array size is %d", m_arraySize);
5317 return false;
5318 }
5319
5320 target = isCube ? GL_TEXTURE_CUBE_MAP
5322 : (is3D ? GL_TEXTURE_3D
5323 : (is1D ? (isArray ? GL_TEXTURE_1D_ARRAY : GL_TEXTURE_1D)
5324 : (isArray ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D)));
5325
5326 if (m_flags.testFlag(ExternalOES))
5328 else if (m_flags.testFlag(TextureRectangleGL))
5330
5331 mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
5333
5334 if (isCompressed) {
5335 if (m_flags.testFlag(UsedWithLoadStore)) {
5336 qWarning("Compressed texture cannot be used with image load/store");
5337 return false;
5338 }
5340 if (!glintformat) {
5341 qWarning("Compressed format %d not mappable to GL compressed format", m_format);
5342 return false;
5343 }
5345 glformat = GL_RGBA;
5346 } else {
5347 toGlTextureFormat(m_format, rhiD->caps,
5349 }
5350
5352
5354
5355 if (adjustedSize)
5356 *adjustedSize = size;
5357
5358 return true;
5359}
5360
5362{
5363 QSize size;
5364 if (!prepareCreate(&size))
5365 return false;
5366
5368 rhiD->f->glGenTextures(1, &texture);
5369
5370 const bool isCube = m_flags.testFlag(CubeMap);
5371 const bool isArray = m_flags.testFlag(QRhiTexture::TextureArray);
5372 const bool is3D = m_flags.testFlag(ThreeDimensional);
5373 const bool hasMipMaps = m_flags.testFlag(MipMapped);
5374 const bool isCompressed = rhiD->isCompressedFormat(m_format);
5375 const bool is1D = m_flags.testFlag(OneDimensional);
5376
5377 if (!isCompressed) {
5378 rhiD->f->glBindTexture(target, texture);
5379 if (!m_flags.testFlag(UsedWithLoadStore)) {
5380 if (is1D) {
5381 for (int level = 0; level < mipLevelCount; ++level) {
5382 const QSize mipSize = rhiD->q->sizeForMipLevel(level, size);
5383 if (isArray)
5384 rhiD->f->glTexImage2D(target, level, GLint(glintformat), mipSize.width(),
5385 qMax(0, m_arraySize), 0, glformat, gltype, nullptr);
5386 else
5387 rhiD->glTexImage1D(target, level, GLint(glintformat), mipSize.width(), 0,
5388 glformat, gltype, nullptr);
5389 }
5390 } else if (is3D || isArray) {
5391 const int layerCount = is3D ? qMax(1, m_depth) : qMax(0, m_arraySize);
5392 if (hasMipMaps) {
5393 for (int level = 0; level != mipLevelCount; ++level) {
5394 const QSize mipSize = rhiD->q->sizeForMipLevel(level, size);
5395 rhiD->f->glTexImage3D(target, level, GLint(glintformat), mipSize.width(), mipSize.height(), layerCount,
5396 0, glformat, gltype, nullptr);
5397 }
5398 } else {
5399 rhiD->f->glTexImage3D(target, 0, GLint(glintformat), size.width(), size.height(), layerCount,
5400 0, glformat, gltype, nullptr);
5401 }
5402 } else if (hasMipMaps || isCube) {
5403 const GLenum faceTargetBase = isCube ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
5404 for (int layer = 0, layerCount = isCube ? 6 : 1; layer != layerCount; ++layer) {
5405 for (int level = 0; level != mipLevelCount; ++level) {
5406 const QSize mipSize = rhiD->q->sizeForMipLevel(level, size);
5407 rhiD->f->glTexImage2D(faceTargetBase + uint(layer), level, GLint(glintformat),
5408 mipSize.width(), mipSize.height(), 0,
5409 glformat, gltype, nullptr);
5410 }
5411 }
5412 } else {
5413 rhiD->f->glTexImage2D(target, 0, GLint(glintformat), size.width(), size.height(),
5414 0, glformat, gltype, nullptr);
5415 }
5416 } else {
5417 // Must be specified with immutable storage functions otherwise
5418 // bindImageTexture may fail. Also, the internal format must be a
5419 // sized format here.
5420 if (is1D && !isArray)
5421 rhiD->glTexStorage1D(target, mipLevelCount, glsizedintformat, size.width());
5422 else if (!is1D && (is3D || isArray))
5423 rhiD->f->glTexStorage3D(target, mipLevelCount, glsizedintformat, size.width(), size.height(),
5424 is3D ? qMax(1, m_depth) : qMax(0, m_arraySize));
5425 else
5426 rhiD->f->glTexStorage2D(target, mipLevelCount, glsizedintformat, size.width(),
5427 is1D ? qMax(0, m_arraySize) : size.height());
5428 }
5429 specified = true;
5430 } else {
5431 // Cannot use glCompressedTexImage2D without valid data, so defer.
5432 // Compressed textures will not be used as render targets so this is
5433 // not an issue.
5434 specified = false;
5435 }
5436
5437 owns = true;
5438
5439 generation += 1;
5440 rhiD->registerResource(this);
5441 return true;
5442}
5443
5445{
5446 const uint textureId = uint(src.object);
5447 if (textureId == 0)
5448 return false;
5449
5450 if (!prepareCreate())
5451 return false;
5452
5453 texture = textureId;
5454 specified = true;
5455 zeroInitialized = true;
5456
5457 owns = false;
5458
5459 generation += 1;
5461 rhiD->registerResource(this);
5462 return true;
5463}
5464
5466{
5467 return {texture, 0};
5468}
5469
5472 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
5473{
5474}
5475
5477{
5478 destroy();
5479}
5480
5482{
5484 if (rhiD)
5485 rhiD->unregisterResource(this);
5486}
5487
5489{
5496
5497 generation += 1;
5499 rhiD->registerResource(this, false);
5500 return true;
5501}
5502
5503// dummy, no Vulkan-style RenderPass+Framebuffer concept here
5506{
5507}
5508
5510{
5511 destroy();
5512}
5513
5515{
5517 if (rhiD)
5518 rhiD->unregisterResource(this);
5519}
5520
5522{
5523 Q_UNUSED(other);
5524 return true;
5525}
5526
5528{
5531 rhiD->registerResource(rpD, false);
5532 return rpD;
5533}
5534
5536{
5537 return {};
5538}
5539
5541 : QRhiSwapChainRenderTarget(rhi, swapchain),
5542 d(rhi)
5543{
5544}
5545
5547{
5548 destroy();
5549}
5550
5552{
5553 // nothing to do here
5554}
5555
5557{
5558 return d.pixelSize;
5559}
5560
5562{
5563 return d.dpr;
5564}
5565
5567{
5568 return d.sampleCount;
5569}
5570
5573 Flags flags)
5575 d(rhi)
5576{
5577}
5578
5580{
5581 destroy();
5582}
5583
5585{
5586 if (!framebuffer)
5587 return;
5588
5591
5592 e.textureRenderTarget.framebuffer = framebuffer;
5593
5594 framebuffer = 0;
5595
5597 if (rhiD) {
5598 rhiD->releaseQueue.append(e);
5599 rhiD->unregisterResource(this);
5600 }
5601}
5602
5604{
5607 rhiD->registerResource(rpD, false);
5608 return rpD;
5609}
5610
5612{
5614
5615 if (framebuffer)
5616 destroy();
5617
5618 const bool hasColorAttachments = m_desc.colorAttachmentCount() > 0;
5619 Q_ASSERT(hasColorAttachments || m_desc.depthTexture());
5621 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
5622
5623 if (hasColorAttachments) {
5624 const int count = int(m_desc.colorAttachmentCount());
5625 if (count > rhiD->caps.maxDrawBuffers) {
5626 qWarning("QGles2TextureRenderTarget: Too many color attachments (%d, max is %d)",
5627 count, rhiD->caps.maxDrawBuffers);
5628 }
5629 }
5630 if (m_desc.depthTexture() && !rhiD->caps.depthTexture)
5631 qWarning("QGles2TextureRenderTarget: Depth texture is not supported and will be ignored");
5632
5633 if (!rhiD->ensureContext())
5634 return false;
5635
5636 rhiD->f->glGenFramebuffers(1, &framebuffer);
5637 rhiD->f->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
5638
5639 d.colorAttCount = 0;
5640 int attIndex = 0;
5641 int multiViewCount = 0;
5642 for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
5643 d.colorAttCount += 1;
5644 const QRhiColorAttachment &colorAtt(*it);
5645 QRhiTexture *texture = colorAtt.texture();
5646 QRhiRenderBuffer *renderBuffer = colorAtt.renderBuffer();
5647 Q_ASSERT(texture || renderBuffer);
5648 if (texture) {
5650 Q_ASSERT(texD->texture && texD->specified);
5651 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional) || texD->flags().testFlag(QRhiTexture::TextureArray)) {
5652 if (colorAtt.multiViewCount() < 2) {
5653 rhiD->f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), texD->texture,
5654 colorAtt.level(), colorAtt.layer());
5655 } else {
5656 multiViewCount = colorAtt.multiViewCount();
5657 rhiD->glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), texD->texture,
5658 colorAtt.level(), colorAtt.layer(), colorAtt.multiViewCount());
5659 }
5660 } else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
5661 rhiD->glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex),
5662 texD->target + uint(colorAtt.layer()), texD->texture,
5663 colorAtt.level());
5664 } else {
5665 const GLenum faceTargetBase = texD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
5666 rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
5667 texD->texture, colorAtt.level());
5668 }
5669 if (attIndex == 0) {
5670 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
5671 d.sampleCount = 1;
5672 }
5673 } else if (renderBuffer) {
5674 QGles2RenderBuffer *rbD = QRHI_RES(QGles2RenderBuffer, renderBuffer);
5675 rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), GL_RENDERBUFFER, rbD->renderbuffer);
5676 if (attIndex == 0) {
5677 d.pixelSize = rbD->pixelSize();
5678 d.sampleCount = rbD->samples;
5679 }
5680 }
5681 }
5682
5683 if (hasDepthStencil) {
5684 if (m_desc.depthStencilBuffer()) {
5686 if (rhiD->caps.needsDepthStencilCombinedAttach) {
5687 rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
5688 depthRbD->renderbuffer);
5689 } else {
5690 rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
5691 depthRbD->renderbuffer);
5692 if (depthRbD->stencilRenderbuffer)
5693 rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
5694 depthRbD->stencilRenderbuffer);
5695 else // packed
5696 rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
5697 depthRbD->renderbuffer);
5698 }
5699 if (d.colorAttCount == 0) {
5700 d.pixelSize = depthRbD->pixelSize();
5701 d.sampleCount = depthRbD->samples;
5702 }
5703 } else {
5705 if (multiViewCount < 2) {
5706 rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexD->target,
5707 depthTexD->texture, 0);
5708 } else {
5709 // This path is OpenGL (ES) 3.0+ and specific to multiview, so
5710 // needsDepthStencilCombinedAttach is not a thing. The depth
5711 // texture here must be an array with at least multiViewCount
5712 // elements, and the format should be D24 or D32F for depth
5713 // only, or D24S8 for depth and stencil.
5714 rhiD->glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexD->texture,
5715 0, 0, multiViewCount);
5716 if (rhiD->isStencilSupportingFormat(depthTexD->format())) {
5717 rhiD->glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexD->texture,
5718 0, 0, multiViewCount);
5719 }
5720 }
5721 if (d.colorAttCount == 0) {
5722 d.pixelSize = depthTexD->pixelSize();
5723 d.sampleCount = 1;
5724 }
5725 }
5726 d.dsAttCount = 1;
5727 } else {
5728 d.dsAttCount = 0;
5729 }
5730
5731 d.dpr = 1;
5733
5734 GLenum status = rhiD->f->glCheckFramebufferStatus(GL_FRAMEBUFFER);
5735 if (status != GL_NO_ERROR && status != GL_FRAMEBUFFER_COMPLETE) {
5736 qWarning("Framebuffer incomplete: 0x%x", status);
5737 return false;
5738 }
5739
5740 QRhiRenderTargetAttachmentTracker::updateResIdList<QGles2Texture, QGles2RenderBuffer>(m_desc, &d.currentResIdList);
5741
5742 rhiD->registerResource(this);
5743 return true;
5744}
5745
5747{
5748 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QGles2Texture, QGles2RenderBuffer>(m_desc, d.currentResIdList))
5749 const_cast<QGles2TextureRenderTarget *>(this)->create();
5750
5751 return d.pixelSize;
5752}
5753
5755{
5756 return d.dpr;
5757}
5758
5760{
5761 return d.sampleCount;
5762}
5763
5766{
5767}
5768
5770{
5771 destroy();
5772}
5773
5775{
5777 if (rhiD)
5778 rhiD->unregisterResource(this);
5779}
5780
5782{
5784 if (!rhiD->sanityCheckShaderResourceBindings(this))
5785 return false;
5786
5787 hasDynamicOffset = false;
5788 for (int i = 0, ie = m_bindings.size(); i != ie; ++i) {
5791 if (b->u.ubuf.hasDynamicOffset) {
5792 hasDynamicOffset = true;
5793 break;
5794 }
5795 }
5796 }
5797
5798 rhiD->updateLayoutDesc(this);
5799
5800 generation += 1;
5801 rhiD->registerResource(this, false);
5802 return true;
5803}
5804
5806{
5807 Q_UNUSED(flags);
5808 generation += 1;
5809}
5810
5813{
5814}
5815
5817{
5818 destroy();
5819}
5820
5822{
5823 if (!program)
5824 return;
5825
5828
5829 e.pipeline.program = program;
5830
5831 program = 0;
5832 uniforms.clear();
5833 samplers.clear();
5834
5836 if (rhiD) {
5837 rhiD->releaseQueue.append(e);
5838 rhiD->unregisterResource(this);
5839 }
5840}
5841
5842static inline bool isGraphicsStage(const QRhiShaderStage &shaderStage)
5843{
5844 const QRhiShaderStage::Type t = shaderStage.type();
5845 return t == QRhiShaderStage::Vertex
5850}
5851
5853{
5855
5856 if (program)
5857 destroy();
5858
5859 if (!rhiD->ensureContext())
5860 return false;
5861
5862 rhiD->pipelineCreationStart();
5863 if (!rhiD->sanityCheckGraphicsPipeline(this))
5864 return false;
5865
5867
5868 program = rhiD->f->glCreateProgram();
5869
5870 enum {
5871 VtxIdx = 0,
5872 TCIdx,
5873 TEIdx,
5874 GeomIdx,
5875 FragIdx,
5876 LastIdx
5877 };
5878 const auto descIdxForStage = [](const QRhiShaderStage &shaderStage) {
5879 switch (shaderStage.type()) {
5881 return VtxIdx;
5883 return TCIdx;
5885 return TEIdx;
5887 return GeomIdx;
5889 return FragIdx;
5890 default:
5891 break;
5892 }
5893 Q_UNREACHABLE_RETURN(VtxIdx);
5894 };
5895 QShaderDescription desc[LastIdx];
5896 QShader::SeparateToCombinedImageSamplerMappingList samplerMappingList[LastIdx];
5897 bool vertexFragmentOnly = true;
5898 for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
5899 if (isGraphicsStage(shaderStage)) {
5900 const int idx = descIdxForStage(shaderStage);
5901 if (idx != VtxIdx && idx != FragIdx)
5902 vertexFragmentOnly = false;
5903 QShader shader = shaderStage.shader();
5904 QShaderVersion shaderVersion;
5905 desc[idx] = shader.description();
5906 if (!rhiD->shaderSource(shaderStage, &shaderVersion).isEmpty()) {
5907 samplerMappingList[idx] = shader.separateToCombinedImageSamplerMappingList(
5908 { QShader::GlslShader, shaderVersion, shaderStage.shaderVariant() });
5909 }
5910 }
5911 }
5912
5913 QByteArray cacheKey;
5914 QRhiGles2::ProgramCacheResult cacheResult = rhiD->tryLoadFromDiskOrPipelineCache(m_shaderStages.constData(),
5916 program,
5917 desc[VtxIdx].inputVariables(),
5918 &cacheKey);
5919 if (cacheResult == QRhiGles2::ProgramCacheError)
5920 return false;
5921
5922 if (cacheResult == QRhiGles2::ProgramCacheMiss) {
5923 for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
5924 if (isGraphicsStage(shaderStage)) {
5925 if (!rhiD->compileShader(program, shaderStage, nullptr))
5926 return false;
5927 }
5928 }
5929
5930 // important when GLSL <= 150 is used that does not have location qualifiers
5931 for (const QShaderDescription::InOutVariable &inVar : desc[VtxIdx].inputVariables())
5932 rhiD->f->glBindAttribLocation(program, GLuint(inVar.location), inVar.name);
5933
5934 if (vertexFragmentOnly)
5935 rhiD->sanityCheckVertexFragmentInterface(desc[VtxIdx], desc[FragIdx]);
5936
5937 if (!rhiD->linkProgram(program))
5938 return false;
5939
5940 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave)) {
5941 // force replacing existing cache entry (if there is one, then
5942 // something is wrong with it, as there was no hit)
5943 rhiD->trySaveToPipelineCache(program, cacheKey, true);
5944 } else {
5945 // legacy QOpenGLShaderProgram style behavior: the "pipeline cache"
5946 // was not enabled, so instead store to the Qt 5 disk cache
5947 rhiD->trySaveToDiskCache(program, cacheKey);
5948 }
5949 } else {
5950 Q_ASSERT(cacheResult == QRhiGles2::ProgramCacheHit);
5951 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave)) {
5952 // just so that it ends up in the pipeline cache also when the hit was
5953 // from the disk cache
5954 rhiD->trySaveToPipelineCache(program, cacheKey);
5955 }
5956 }
5957
5958 // Use the same work area for the vertex & fragment stages, thus ensuring
5959 // that we will not do superfluous glUniform calls for uniforms that are
5960 // present in both shaders.
5961 QDuplicateTracker<int, 256> activeUniformLocations;
5962
5963 for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
5964 if (isGraphicsStage(shaderStage)) {
5965 const int idx = descIdxForStage(shaderStage);
5966 for (const QShaderDescription::UniformBlock &ub : desc[idx].uniformBlocks())
5967 rhiD->gatherUniforms(program, ub, &activeUniformLocations, &uniforms);
5968 for (const QShaderDescription::InOutVariable &v : desc[idx].combinedImageSamplers())
5969 rhiD->gatherSamplers(program, v, &samplers);
5970 for (const QShader::SeparateToCombinedImageSamplerMapping &mapping : samplerMappingList[idx])
5971 rhiD->gatherGeneratedSamplers(program, mapping, &samplers);
5972 }
5973 }
5974
5975 std::sort(uniforms.begin(), uniforms.end(),
5977 {
5978 return a.offset < b.offset;
5979 });
5980
5981 memset(uniformState, 0, sizeof(uniformState));
5982
5983 currentSrb = nullptr;
5985
5986 rhiD->pipelineCreationEnd();
5987 generation += 1;
5988 rhiD->registerResource(this);
5989 return true;
5990}
5991
5993 : QRhiComputePipeline(rhi)
5994{
5995}
5996
5998{
5999 destroy();
6000}
6001
6003{
6004 if (!program)
6005 return;
6006
6009
6010 e.pipeline.program = program;
6011
6012 program = 0;
6013 uniforms.clear();
6014 samplers.clear();
6015
6017 if (rhiD) {
6018 rhiD->releaseQueue.append(e);
6019 rhiD->unregisterResource(this);
6020 }
6021}
6022
6024{
6026
6027 if (program)
6028 destroy();
6029
6030 if (!rhiD->ensureContext())
6031 return false;
6032
6033 rhiD->pipelineCreationStart();
6034
6037 QShaderVersion shaderVersion;
6038 if (!rhiD->shaderSource(m_shaderStage, &shaderVersion).isEmpty()) {
6040 { QShader::GlslShader, shaderVersion, m_shaderStage.shaderVariant() });
6041 }
6042
6043 program = rhiD->f->glCreateProgram();
6044
6045 QByteArray cacheKey;
6046 QRhiGles2::ProgramCacheResult cacheResult = rhiD->tryLoadFromDiskOrPipelineCache(&m_shaderStage, 1, program, {}, &cacheKey);
6047 if (cacheResult == QRhiGles2::ProgramCacheError)
6048 return false;
6049
6050 if (cacheResult == QRhiGles2::ProgramCacheMiss) {
6051 if (!rhiD->compileShader(program, m_shaderStage, nullptr))
6052 return false;
6053
6054 if (!rhiD->linkProgram(program))
6055 return false;
6056
6057 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave)) {
6058 // force replacing existing cache entry (if there is one, then
6059 // something is wrong with it, as there was no hit)
6060 rhiD->trySaveToPipelineCache(program, cacheKey, true);
6061 } else {
6062 // legacy QOpenGLShaderProgram style behavior: the "pipeline cache"
6063 // was not enabled, so instead store to the Qt 5 disk cache
6064 rhiD->trySaveToDiskCache(program, cacheKey);
6065 }
6066 } else {
6067 Q_ASSERT(cacheResult == QRhiGles2::ProgramCacheHit);
6068 if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave)) {
6069 // just so that it ends up in the pipeline cache also when the hit was
6070 // from the disk cache
6071 rhiD->trySaveToPipelineCache(program, cacheKey);
6072 }
6073 }
6074
6075 QDuplicateTracker<int, 256> activeUniformLocations;
6076 for (const QShaderDescription::UniformBlock &ub : csDesc.uniformBlocks())
6077 rhiD->gatherUniforms(program, ub, &activeUniformLocations, &uniforms);
6079 rhiD->gatherSamplers(program, v, &samplers);
6080 for (const QShader::SeparateToCombinedImageSamplerMapping &mapping : csSamplerMappingList)
6081 rhiD->gatherGeneratedSamplers(program, mapping, &samplers);
6082
6083 // storage images and buffers need no special steps here
6084
6085 memset(uniformState, 0, sizeof(uniformState));
6086
6087 currentSrb = nullptr;
6089
6090 rhiD->pipelineCreationEnd();
6091 generation += 1;
6092 rhiD->registerResource(this);
6093 return true;
6094}
6095
6097 : QRhiCommandBuffer(rhi)
6098{
6099 resetState();
6100}
6101
6103{
6104 destroy();
6105}
6106
6108{
6109 // nothing to do here
6110}
6111
6113 : QRhiSwapChain(rhi),
6114 rt(rhi, this),
6115 rtLeft(rhi, this),
6116 rtRight(rhi, this),
6117 cb(rhi)
6118{
6119}
6120
6122{
6123 destroy();
6124}
6125
6127{
6129 if (rhiD)
6130 rhiD->unregisterResource(this);
6131}
6132
6134{
6135 return &cb;
6136}
6137
6139{
6140 return &rt;
6141}
6142
6144{
6145 if (targetBuffer == LeftBuffer)
6146 return rtLeft.d.isValid() ? &rtLeft : &rt;
6147 else if (targetBuffer == RightBuffer)
6148 return rtRight.d.isValid() ? &rtRight : &rt;
6149 else
6150 Q_UNREACHABLE_RETURN(nullptr);
6151}
6152
6154{
6156 return m_window->size() * m_window->devicePixelRatio();
6157}
6158
6160{
6161 return f == SDR;
6162}
6163
6165{
6168 rhiD->registerResource(rpD, false);
6169 return rpD;
6170}
6171
6173{
6174 rt->setRenderPassDescriptor(m_renderPassDesc); // for the public getter in QRhiRenderTarget
6177 rt->d.dpr = float(m_window->devicePixelRatio());
6178 rt->d.sampleCount = qBound(1, m_sampleCount, 64);
6179 rt->d.colorAttCount = 1;
6180 rt->d.dsAttCount = m_depthStencil ? 1 : 0;
6182}
6183
6185{
6186 // can be called multiple times due to window resizes
6187 const bool needsRegistration = !surface || surface != m_window;
6188 if (surface && surface != m_window)
6189 destroy();
6190
6191 surface = m_window;
6194
6197 {
6200 }
6201
6203
6204 if (m_window->format().stereo()) {
6209 }
6210
6211 frameCount = 0;
6212
6213 // The only reason to register this fairly fake gl swapchain
6214 // object with no native resources underneath is to be able to
6215 // implement a safe destroy().
6216 if (needsRegistration) {
6218 rhiD->registerResource(this, false);
6219 }
6220
6221 return true;
6222}
6223
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
float greenF() const noexcept
Returns the green color component of this color.
Definition qcolor.cpp:1643
float redF() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1611
float alphaF() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1497
float blueF() const noexcept
Returns the blue color component of this color.
Definition qcolor.cpp:1675
bool hasSeen(const T &s)
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1202
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:925
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1279
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1209
iterator erase(const_iterator it)
Definition qhash.h:1223
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:949
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:926
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
\inmodule QtGui
Definition qimage.h:37
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition qimage.cpp:1197
Definition qlist.h:74
bool isEmpty() const noexcept
Definition qlist.h:390
void append(parameter_type t)
Definition qlist.h:441
Definition qmap.h:186
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
const_iterator cend() const
Definition qmap.h:604
const_iterator cbegin() const
Definition qmap.h:600
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
\inmodule QtGui
void setFormat(const QSurfaceFormat &format)
Sets the offscreen surface format.
\inmodule QtGui
bool create()
Attempts to create the OpenGL context with the current configuration.
QSurfaceFormat format() const
Returns the format of the underlying platform context, if create() has been called.
QOpenGLContext * shareContext() const
Returns the share context this context was created with.
void setFormat(const QSurfaceFormat &format)
Sets the format the OpenGL context should be compatible with.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
QScreen * screen() const
Returns the screen the context was created for.
QOpenGLProgramBinarySupportCheck * get(QOpenGLContext *context)
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0, otherwise returns false.
Definition qpoint.h:122
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:132
quint32 size() const
Definition qrhi_p.h:344
const char * constData() const
Definition qrhi_p.h:340
\inmodule QtGui
Definition qrhi.h:834
UsageFlags m_usage
Definition qrhi.h:876
Type m_type
Definition qrhi.h:875
Type
Specifies storage type of buffer resource.
Definition qrhi.h:836
@ Dynamic
Definition qrhi.h:839
@ IndexBuffer
Definition qrhi.h:844
@ VertexBuffer
Definition qrhi.h:843
@ UniformBuffer
Definition qrhi.h:845
@ StorageBuffer
Definition qrhi.h:846
quint32 m_size
Definition qrhi.h:877
\inmodule QtGui
Definition qrhi.h:568
QRhiRenderBuffer * renderBuffer() const
Definition qrhi.h:577
int multiViewCount() const
Definition qrhi.h:595
int resolveLevel() const
Definition qrhi.h:592
QRhiTexture * texture() const
Definition qrhi.h:574
int resolveLayer() const
Definition qrhi.h:589
QRhiTexture * resolveTexture() const
Definition qrhi.h:586
int level() const
Definition qrhi.h:583
int layer() const
Definition qrhi.h:580
\inmodule QtGui
Definition qrhi.h:1614
QPair< QRhiBuffer *, quint32 > VertexInput
Synonym for QPair<QRhiBuffer *, quint32>.
Definition qrhi.h:1643
@ DoNotTrackResourcesForCompute
Definition qrhi.h:1623
QPair< int, quint32 > DynamicOffset
Synonym for QPair<int, quint32>.
Definition qrhi.h:1639
IndexFormat
Specifies the index data type.
Definition qrhi.h:1616
\inmodule QtGui
Definition qrhi.h:1585
QRhiShaderStage m_shaderStage
Definition qrhi.h:1607
QRhiShaderResourceBindings * m_shaderResourceBindings
Definition qrhi.h:1608
\inmodule QtGui
Definition qrhi.h:44
float depthClearValue() const
Definition qrhi.h:49
quint32 stencilClearValue() const
Definition qrhi.h:52
\inmodule QtGui
\variable QRhiGles2InitParams::format
QHash< QRhiShaderStage, uint > m_shaderCache
QRhiStats statistics() override
bool contextLost
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub, QDuplicateTracker< int, 256 > *activeUniformLocations, QGles2UniformDescriptionVector *dst)
void registerUniformIfActive(const QShaderDescription::BlockVariable &var, const QByteArray &namePrefix, int binding, int baseOffset, GLuint program, QDuplicateTracker< int, 256 > *activeUniformLocations, QGles2UniformDescriptionVector *dst)
const GLvoid const GLvoid GLuint
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) override
QOpenGLContext * maybeShareContext
void trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *bufD, QGles2Buffer::Access access)
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override
void enqueueBarriersForPass(QGles2CommandBuffer *cbD)
QList< DeferredReleaseEntry > releaseQueue
int resourceLimit(QRhi::ResourceLimit limit) const override
void setVertexInput(QRhiCommandBuffer *cb, int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat) override
bool isFeatureSupported(QRhi::Feature feature) const override
QRhiGraphicsPipeline * createGraphicsPipeline() override
void bindShaderResources(QGles2CommandBuffer *cbD, QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs, QRhiShaderResourceBindings *srb, const uint *dynOfsPairs, int dynOfsCount)
bool create(QRhi::Flags flags) override
void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker, QGles2Texture *texD, QRhiPassResourceTracker::TextureAccess access, QRhiPassResourceTracker::TextureStage stage)
void executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2GraphicsPipeline *psD)
QRhiDriverInfo driverInfo() const override
QSurfaceFormat requestedFormat
QHash< QByteArray, PipelineCacheData > m_pipelineCache
bool isProgramBinaryDiskCacheEnabled() const
bool needsMakeCurrentDueToSwap
void trackedImageBarrier(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Texture::Access access)
void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, QGles2Buffer *bufD, QRhiPassResourceTracker::BufferAccess access, QRhiPassResourceTracker::BufferStage stage)
QRhiComputePipeline * createComputePipeline() override
QRhiDriverInfo driverInfoStruct
QSurface * evaluateFallbackSurface() const
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void sanityCheckVertexFragmentInterface(const QShaderDescription &vsDesc, const QShaderDescription &fsDesc)
QRhiGles2NativeHandles nativeHandlesStruct
QMatrix4x4 clipSpaceCorrMatrix() const override
QRhi::FrameOpResult finish() override
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override
QList< int > supportedSampleCounts() const override
int effectiveSampleCount(int sampleCount) const
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v, QGles2SamplerDescriptionVector *dst)
QSet< GLint > supportedCompressedFormats
QRhiSwapChain * createSwapChain() override
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override
void destroy() override
QRhiRenderBuffer * createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags, QRhiTexture::Format backingFormatHint) override
void executeCommandBuffer(QRhiCommandBuffer *cb)
void setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps) override
QSurface * fallbackSurface
QRhiGles2(QRhiGles2InitParams *params, QRhiGles2NativeHandles *importDevice=nullptr)
QRhi::Flags rhiFlags
void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey)
struct QRhiGles2::Caps caps
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, QShaderVersion *shaderVersion)
QRhiTexture * createTexture(QRhiTexture::Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, QRhiTexture::Flags flags) override
void bindCombinedSampler(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Sampler *samplerD, void *ps, uint psGeneration, int glslLocation, int *texUnit, bool *activeTexUnitAltered)
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override
QRhiTextureRenderTarget * createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override
QOpenGLContext * ctx
QRhiSampler * createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w) override
void beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
QGles2SwapChain * currentSwapChain
bool isDeviceLost() const override
QRhiShaderResourceBindings * createShaderResourceBindings() override
bool isYUpInNDC() const override
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
bool makeThreadLocalNativeContextCurrent() override
int ubufAlignment() const override
void beginExternal(QRhiCommandBuffer *cb) override
void endExternal(QRhiCommandBuffer *cb) override
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override
QByteArray shaderSource(const QRhiShaderStage &shaderStage, QShaderVersion *shaderVersion)
QRhiBuffer * createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size) override
bool importedContext
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
bool ensureContext(QSurface *surface=nullptr) const
void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
ProgramCacheResult tryLoadFromDiskOrPipelineCache(const QRhiShaderStage *stages, int stageCount, GLuint program, const QVector< QShaderDescription::InOutVariable > &inputVars, QByteArray *cacheKey)
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
bool isYUpInFramebuffer() const override
bool linkProgram(GLuint program)
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override
@ ProgramCacheError
QGles2RenderTargetData * enqueueBindFramebuffer(QRhiRenderTarget *rt, QGles2CommandBuffer *cbD, bool *wantsColorClear=nullptr, bool *wantsDsClear=nullptr)
void debugMarkEnd(QRhiCommandBuffer *cb) override
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override
void setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override
void releaseCachedResources() override
bool isClipDepthZeroToOne() const override
void trySaveToPipelineCache(GLuint program, const QByteArray &cacheKey, bool force=false)
void executeDeferredReleases()
QByteArray pipelineCacheData() override
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override
QList< int > supportedSampleCountList
QPointer< QWindow > maybeWindow
void enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cbD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc)
struct QRhiGles2::OffscreenFrame ofr
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override
void setPipelineCacheData(const QByteArray &data) override
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override
void gatherGeneratedSamplers(GLuint program, const QShader::SeparateToCombinedImageSamplerMapping &mapping, QGles2SamplerDescriptionVector *dst)
const QRhiNativeHandles * nativeHandles() override
\inmodule QtGui
Definition qrhi.h:1241
quint32 m_stencilReadMask
Definition qrhi.h:1462
BlendOp
Specifies the blend operation.
Definition qrhi.h:1302
PolygonMode
Specifies the polygon rasterization mode.
Definition qrhi.h:1350
FrontFace
Specifies the front face winding order.
Definition qrhi.h:1267
BlendFactor
Specifies the blend factor.
Definition qrhi.h:1280
StencilOpState m_stencilFront
Definition qrhi.h:1460
quint32 m_stencilWriteMask
Definition qrhi.h:1463
CompareOp
Specifies the depth or stencil comparison function.
Definition qrhi.h:1321
Topology m_topology
Definition qrhi.h:1452
CullMode
Specifies the culling mode.
Definition qrhi.h:1261
QVarLengthArray< QRhiShaderStage, 4 > m_shaderStages
Definition qrhi.h:1471
QRhiVertexInputLayout m_vertexInputLayout
Definition qrhi.h:1472
QVarLengthArray< TargetBlend, 8 > m_targetBlends
Definition qrhi.h:1455
QRhiShaderResourceBindings * m_shaderResourceBindings
Definition qrhi.h:1473
PolygonMode m_polygonMode
Definition qrhi.h:1469
float m_slopeScaledDepthBias
Definition qrhi.h:1467
Topology
Specifies the primitive topology.
Definition qrhi.h:1251
StencilOpState m_stencilBack
Definition qrhi.h:1461
FrontFace m_frontFace
Definition qrhi.h:1454
StencilOp
Specifies the stencil operation.
Definition qrhi.h:1332
int m_patchControlPointCount
Definition qrhi.h:1468
CullMode m_cullMode
Definition qrhi.h:1453
CompareOp m_depthOp
Definition qrhi.h:1458
bool isCompressedFormat(QRhiTexture::Format format) const
Definition qrhi.cpp:7731
static const QRhiShaderResourceBinding::Data * shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
Definition qrhi_p.h:210
quint32 pipelineCacheRhiId() const
Definition qrhi_p.h:186
void compressedFormatInfo(QRhiTexture::Format format, const QSize &size, quint32 *bpl, quint32 *byteSize, QSize *blockDim) const
Definition qrhi.cpp:7738
static const int MAX_SHADER_CACHE_ENTRIES
Definition qrhi_p.h:227
qint64 totalPipelineCreationTime() const
Definition qrhi_p.h:202
void textureFormatInfo(QRhiTexture::Format format, const QSize &size, quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const
Definition qrhi.cpp:7858
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages)
Definition qrhi.cpp:10651
TextureIterator cendTextures() const
Definition qrhi_p.h:673
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
Definition qrhi.cpp:10632
BufferIterator cbeginBuffers() const
Definition qrhi_p.h:662
BufferIterator cendBuffers() const
Definition qrhi_p.h:663
TextureIterator cbeginTextures() const
Definition qrhi_p.h:672
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
Definition qrhi.cpp:10560
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
Definition qrhi.cpp:10599
int layer() const
Definition qrhi.h:773
QRhiTexture * texture() const
Definition qrhi.h:770
int level() const
Definition qrhi.h:776
\inmodule QtGui
Definition qrhi.h:1071
Flags flags() const
Definition qrhi.h:1098
void setPixelSize(const QSize &sz)
Sets the size (in pixels) to sz.
Definition qrhi.h:1093
QSize pixelSize() const
Definition qrhi.h:1092
int m_sampleCount
Definition qrhi.h:1111
QRhiTexture::Format m_backingFormatHint
Definition qrhi.h:1113
QSize m_pixelSize
Definition qrhi.h:1110
Type
Specifies the type of the renderbuffer.
Definition qrhi.h:1073
virtual bool create()=0
Creates the corresponding native graphics resources.
@ UsedWithSwapChainOnly
Definition qrhi.h:1079
Flags m_flags
Definition qrhi.h:1112
\inmodule QtGui
Definition qrhi.h:1119
\inmodule QtGui
Definition qrhi.h:1135
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Sets the QRhiRenderPassDescriptor desc for use with this render target.
Definition qrhi.h:1142
QRhiRenderPassDescriptor * m_renderPassDesc
Definition qrhi.h:1146
QVarLengthArray< BufferOp, BUFFER_OPS_STATIC_ALLOC > bufferOps
Definition qrhi_p.h:508
QVarLengthArray< TextureOp, TEXTURE_OPS_STATIC_ALLOC > textureOps
Definition qrhi_p.h:512
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
Definition qrhi_p.h:523
\inmodule QtGui
Definition qrhi.h:1694
\inmodule QtGui
Definition qrhi.h:792
@ SwapChainRenderTarget
Definition qrhi.h:800
@ TextureRenderTarget
Definition qrhi.h:801
virtual Type resourceType() const =0
QRhiImplementation * m_rhi
Definition qrhi.h:828
\inmodule QtGui
Definition qrhi.h:1007
Filter m_minFilter
Definition qrhi.h:1062
Filter
Specifies the minification, magnification, or mipmap filtering.
Definition qrhi.h:1009
AddressMode m_addressV
Definition qrhi.h:1065
Filter m_mipmapMode
Definition qrhi.h:1063
AddressMode m_addressU
Definition qrhi.h:1064
AddressMode
Specifies the addressing mode.
Definition qrhi.h:1015
@ ClampToEdge
Definition qrhi.h:1017
CompareOp
Specifies the texture comparison function.
Definition qrhi.h:1021
@ LessOrEqual
Definition qrhi.h:1025
@ GreaterOrEqual
Definition qrhi.h:1028
CompareOp m_compareOp
Definition qrhi.h:1067
AddressMode m_addressW
Definition qrhi.h:1066
Filter m_magFilter
Definition qrhi.h:1061
\inmodule QtGui
Definition qrhi.h:138
std::array< int, 4 > scissor() const
Definition qrhi.h:143
Type
Specifies type of the shader resource bound to a binding point.
Definition qrhi.h:433
\inmodule QtGui
Definition qrhi.h:1190
QVarLengthArray< QRhiShaderResourceBinding, BINDING_PREALLOC > m_bindings
Definition qrhi.h:1222
\inmodule QtGui
Definition qrhi.h:371
QShader::Variant shaderVariant() const
Definition qrhi.h:392
QShader shader() const
Definition qrhi.h:389
Type
Specifies the type of the shader stage.
Definition qrhi.h:373
@ TessellationControl
Definition qrhi.h:375
@ TessellationEvaluation
Definition qrhi.h:376
Type type() const
Definition qrhi.h:386
\inmodule QtGui
Definition qrhi.h:1150
\inmodule QtGui
Definition qrhi.h:1513
QWindow * m_window
Definition qrhi.h:1572
int m_sampleCount
Definition qrhi.h:1576
QRhiRenderPassDescriptor * m_renderPassDesc
Definition qrhi.h:1577
QSize m_currentPixelSize
Definition qrhi.h:1578
Flags m_flags
Definition qrhi.h:1573
Format
Describes the swapchain format.
Definition qrhi.h:1525
StereoTargetBuffer
Selects the backbuffer to use with a stereoscopic swapchain.
Definition qrhi.h:1531
QRhiRenderBuffer * m_depthStencil
Definition qrhi.h:1575
QPoint destinationTopLeft() const
Definition qrhi.h:749
QPoint sourceTopLeft() const
Definition qrhi.h:740
int destinationLevel() const
Definition qrhi.h:746
int sourceLevel() const
Definition qrhi.h:737
QSize pixelSize() const
Definition qrhi.h:731
int sourceLayer() const
Definition qrhi.h:734
int destinationLayer() const
Definition qrhi.h:743
const QRhiColorAttachment * cbeginColorAttachments() const
Definition qrhi.h:626
QRhiTexture * depthTexture() const
Definition qrhi.h:634
const QRhiColorAttachment * cendColorAttachments() const
Definition qrhi.h:627
QRhiRenderBuffer * depthStencilBuffer() const
Definition qrhi.h:631
qsizetype colorAttachmentCount() const
Definition qrhi.h:629
\inmodule QtGui
Definition qrhi.h:1161
QRhiTextureRenderTargetDescription m_desc
Definition qrhi.h:1183
QRhiTextureRenderTargetDescription description() const
Definition qrhi.h:1171
\inmodule QtGui
Definition qrhi.h:883
QSize m_pixelSize
Definition qrhi.h:995
int m_arraySize
Definition qrhi.h:997
int m_depth
Definition qrhi.h:996
Format format() const
Definition qrhi.h:960
@ ThreeDimensional
Definition qrhi.h:895
@ UsedAsCompressedAtlas
Definition qrhi.h:893
@ UsedWithLoadStore
Definition qrhi.h:892
@ MipMapped
Definition qrhi.h:888
@ OneDimensional
Definition qrhi.h:898
@ TextureArray
Definition qrhi.h:897
@ TextureRectangleGL
Definition qrhi.h:896
@ CubeMap
Definition qrhi.h:887
@ ExternalOES
Definition qrhi.h:894
Format
Specifies the texture format.
Definition qrhi.h:902
@ ASTC_10x8
Definition qrhi.h:947
@ ASTC_12x12
Definition qrhi.h:950
@ ASTC_8x5
Definition qrhi.h:942
@ ASTC_10x5
Definition qrhi.h:945
@ RGBA32F
Definition qrhi.h:914
@ ETC2_RGBA8
Definition qrhi.h:935
@ ASTC_5x5
Definition qrhi.h:939
@ ASTC_4x4
Definition qrhi.h:937
@ ASTC_6x6
Definition qrhi.h:941
@ ASTC_12x10
Definition qrhi.h:949
@ ETC2_RGB8
Definition qrhi.h:933
@ ASTC_5x4
Definition qrhi.h:938
@ RED_OR_ALPHA8
Definition qrhi.h:911
@ ASTC_6x5
Definition qrhi.h:940
@ ASTC_8x8
Definition qrhi.h:944
@ RGBA16F
Definition qrhi.h:913
@ RGB10A2
Definition qrhi.h:918
@ ASTC_10x6
Definition qrhi.h:946
@ ASTC_10x10
Definition qrhi.h:948
@ UnknownFormat
Definition qrhi.h:903
@ ETC2_RGB8A1
Definition qrhi.h:934
@ ASTC_8x6
Definition qrhi.h:943
Flags flags() const
Definition qrhi.h:980
QSize pixelSize() const
Definition qrhi.h:963
Format m_format
Definition qrhi.h:994
Flags m_flags
Definition qrhi.h:999
int m_sampleCount
Definition qrhi.h:998
\inmodule QtGui
Definition qrhi.h:179
quint32 instanceStepRate() const
Definition qrhi.h:195
Classification classification() const
Definition qrhi.h:192
quint32 stride() const
Definition qrhi.h:189
const QRhiVertexInputBinding * bindingAt(qsizetype index) const
Definition qrhi.h:326
const QRhiVertexInputAttribute * cendAttributes() const
Definition qrhi.h:337
const QRhiVertexInputAttribute * cbeginAttributes() const
Definition qrhi.h:336
\inmodule QtGui
Definition qrhi.h:85
ResourceLimit
Describes the resource limit to query.
Definition qrhi.h:1846
@ MaxThreadsPerThreadGroup
Definition qrhi.h:1853
@ MaxThreadGroupZ
Definition qrhi.h:1856
@ FramesInFlight
Definition qrhi.h:1850
@ TextureSizeMin
Definition qrhi.h:1847
@ MaxThreadGroupsPerDimension
Definition qrhi.h:1852
@ MaxAsyncReadbackFrames
Definition qrhi.h:1851
@ TextureArraySizeMax
Definition qrhi.h:1857
@ MaxColorAttachments
Definition qrhi.h:1849
@ MaxThreadGroupY
Definition qrhi.h:1855
@ MaxVertexInputs
Definition qrhi.h:1859
@ MaxThreadGroupX
Definition qrhi.h:1854
@ TextureSizeMax
Definition qrhi.h:1848
@ MaxVertexOutputs
Definition qrhi.h:1860
@ MaxUniformBufferRange
Definition qrhi.h:1858
@ SkipPresent
Definition qrhi.h:1842
Feature
Flag values to indicate what features are supported by the backend currently in use.
Definition qrhi.h:1793
@ HalfAttributes
Definition qrhi.h:1831
@ CustomInstanceStepRate
Definition qrhi.h:1799
@ NonDynamicUniformBuffers
Definition qrhi.h:1801
@ ElementIndexUint
Definition qrhi.h:1805
@ RenderToNonBaseMipLevel
Definition qrhi.h:1815
@ MultisampleRenderBuffer
Definition qrhi.h:1795
@ RenderTo3DTextureSlice
Definition qrhi.h:1823
@ Tessellation
Definition qrhi.h:1825
@ IntAttributes
Definition qrhi.h:1816
@ TextureArrays
Definition qrhi.h:1824
@ PipelineCacheDataLoadSave
Definition qrhi.h:1819
@ ReadBackNonUniformBuffer
Definition qrhi.h:1812
@ MultiView
Definition qrhi.h:1834
@ TexelFetch
Definition qrhi.h:1814
@ TextureArrayRange
Definition qrhi.h:1827
@ RenderToOneDimensionalTexture
Definition qrhi.h:1832
@ BaseVertex
Definition qrhi.h:1809
@ GeometryShader
Definition qrhi.h:1826
@ Compute
Definition qrhi.h:1806
@ OneDimensionalTextureMipmaps
Definition qrhi.h:1830
@ WideLines
Definition qrhi.h:1807
@ TriangleFanTopology
Definition qrhi.h:1811
@ OneDimensionalTextures
Definition qrhi.h:1829
@ ImageDataStride
Definition qrhi.h:1820
@ BaseInstance
Definition qrhi.h:1810
@ DebugMarkers
Definition qrhi.h:1796
@ ReadBackNonBaseMipLevel
Definition qrhi.h:1813
@ MultisampleTexture
Definition qrhi.h:1794
@ ThreeDimensionalTextureMipmaps
Definition qrhi.h:1833
@ NonFourAlignedEffectiveIndexBufferOffset
Definition qrhi.h:1802
@ RedOrAlpha8IsRed
Definition qrhi.h:1804
@ NonFillPolygonMode
Definition qrhi.h:1828
@ Timestamps
Definition qrhi.h:1797
@ ThreeDimensionalTextures
Definition qrhi.h:1822
@ PrimitiveRestart
Definition qrhi.h:1800
@ ReadBackAnyTextureFormat
Definition qrhi.h:1818
@ RenderBufferImport
Definition qrhi.h:1821
@ ScreenSpaceDerivatives
Definition qrhi.h:1817
@ VertexShaderPointSize
Definition qrhi.h:1808
@ NPOTTextureRepeat
Definition qrhi.h:1803
@ Instancing
Definition qrhi.h:1798
static const int MAX_MIP_LEVELS
Definition qrhi.h:1955
FrameOpResult
Describes the result of operations that can have a soft failure.
Definition qrhi.h:1786
@ FrameOpSuccess
Definition qrhi.h:1787
@ FrameOpDeviceLost
Definition qrhi.h:1790
@ FrameOpError
Definition qrhi.h:1788
@ EnablePipelineCacheDataSave
Definition qrhi.h:1781
qsizetype size() const
Definition qset.h:50
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
QList< InOutVariable > inputVariables() const
QList< InOutVariable > outputVariables() const
QList< InOutVariable > combinedImageSamplers() const
QList< UniformBlock > uniformBlocks() const
\inmodule QtGui
Definition qshader.h:32
\inmodule QtGui
Definition qshader.h:81
SeparateToCombinedImageSamplerMappingList separateToCombinedImageSamplerMappingList(const QShaderKey &key) const
\variable QShader::SeparateToCombinedImageSamplerMapping::combinedSamplerName
Definition qshader.cpp:1074
QShaderCode shader(const QShaderKey &key) const
Definition qshader.cpp:365
@ GlslShader
Definition qshader.h:94
QShaderDescription description() const
Definition qshader.cpp:340
Stage
Describes the stage of the graphics pipeline the shader is suitable for.
Definition qshader.h:83
@ GeometryStage
Definition qshader.h:87
@ ComputeStage
Definition qshader.h:89
@ TessellationEvaluationStage
Definition qshader.h:86
@ VertexStage
Definition qshader.h:84
@ FragmentStage
Definition qshader.h:88
@ TessellationControlStage
Definition qshader.h:85
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:123
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1101
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
int minorVersion() const
Returns the minor OpenGL version.
OpenGLContextProfile profile() const
Get the configured OpenGL context profile.
static QSurfaceFormat defaultFormat()
Returns the global default surface format.
int majorVersion() const
Returns the major OpenGL version.
RenderableType renderableType() const
Gets the renderable type.
bool stereo() const
Returns true if stereo buffering is enabled; otherwise returns false.
\inmodule QtGui
Definition qsurface.h:21
SurfaceClass surfaceClass() const
Returns the surface class of this surface.
Definition qsurface.cpp:121
virtual QPlatformSurface * surfaceHandle() const =0
Returns a handle to the platform-specific implementation of the surface.
constexpr size_type size() const noexcept
bool isEmpty() const
const T & at(qsizetype idx) const
void resize(qsizetype sz)
iterator end() noexcept
void append(const T &t)
const T * constData() const
T * data() noexcept
iterator begin() noexcept
const void * constData() const
Definition qvariant.h:446
QSurfaceFormat format() const override
Returns the actual format of this window.
Definition qwindow.cpp:888
QSize size() const override
Returns the size of the window excluding any window frame.
Definition qwindow.h:210
EGLContext ctx
#define this
Definition dialogs.cpp:9
p1 load("image.bmp")
double e
QSet< QString >::iterator it
else opt state
[0]
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
#define Q_STATIC_ASSERT(Condition)
Definition qassert.h:105
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
static int instanceCount
static QString header(const QString &name)
static bool isCubeMap(const DDSHeader &dds)
static const qint64 headerSize
EGLOutputLayerEXT layer
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
Flags
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition qlogging.h:162
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
#define GL_CONTEXT_LOST
Definition qopengl.cpp:30
#define QOPENGLF_APIENTRYP
Definition qopengl.h:265
QOpenGLContext * qt_gl_global_share_context()
#define GL_MAP_READ_BIT
GLboolean GLboolean GLboolean b
typedef GLint(GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program
GLbitfield stages
GLsizei const GLfloat * v
[13]
GLint GLboolean layered
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLsizei samples
GLenum mode
const GLfloat * m
GLenum GLuint GLint level
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLint GLenum GLint components
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLenum GLsizei dataSize
GLuint sampler
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
const GLenum * bufs
GLfloat GLfloat f
#define GL_TEXTURE_3D
GLenum src
const void GLsizei GLsizei stride
GLenum GLuint buffer
GLenum type
GLenum GLenum dst
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY
#define GL_MAP_WRITE_BIT
#define GL_MIN
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLenum access
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum target
GLbitfield flags
#define GL_TEXTURE_2D_MULTISAMPLE
GLenum GLuint texture
GLuint program
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLsizei GLsizei GLenum * binaryFormat
#define GL_TEXTURE_2D_ARRAY
GLint ref
#define GL_MAX
GLuint name
#define GL_TEXTURE_EXTERNAL_OES
GLfloat n
GLint GLsizei GLsizei GLenum format
GLint y
GLsizei GLenum internalFormat
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
void ** params
#define GL_NUM_PROGRAM_BINARY_FORMATS
#define GL_MIRRORED_REPEAT
Definition qopenglext.h:331
#define GL_TEXTURE_COMPARE_FUNC
Definition qopenglext.h:338
#define GL_MAX_VARYING_VECTORS
#define GL_TEXTURE0
Definition qopenglext.h:129
#define GL_MAX_COMPUTE_WORK_GROUP_COUNT
#define GL_FRAGMENT_SHADER
Definition qopenglext.h:609
#define GL_TEXTURE_WRAP_R
Definition qopenglext.h:87
const GLubyte * c
#define GL_DEPTH24_STENCIL8
#define GL_DEPTH_COMPONENT16
Definition qopenglext.h:328
#define GL_TEXTURE_CUBE_MAP
Definition qopenglext.h:170
GLuint renderbuffer
#define GL_PRIMITIVE_RESTART_FIXED_INDEX
#define GL_ONE_MINUS_CONSTANT_ALPHA
Definition qopenglext.h:367
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
GLint void * img
Definition qopenglext.h:233
#define GL_COMPRESSED_TEXTURE_FORMATS
Definition qopenglext.h:186
#define GL_CONSTANT_COLOR
Definition qopenglext.h:364
#define GL_FRAMEBUFFER_SRGB
#define GL_MAX_VERTEX_OUTPUT_COMPONENTS
#define GL_COLOR_ATTACHMENT0
#define GL_DEPTH_STENCIL_ATTACHMENT
#define GL_TEXTURE_CUBE_MAP_SEAMLESS
GLuint shader
Definition qopenglext.h:665
#define GL_COMPARE_REF_TO_TEXTURE
Definition qopenglext.h:894
#define GL_SHADER_STORAGE_BUFFER
#define GL_ALL_BARRIER_BITS
GLenum GLsizei len
#define GL_MAX_VERTEX_ATTRIBS
Definition qopenglext.h:606
#define GL_STENCIL_INDEX8
#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
Definition qopenglext.h:611
typedef GLbitfield(APIENTRYP PFNGLQUERYMATRIXXOESPROC)(GLfixed *mantissa
GLint limit
#define GL_ARRAY_BUFFER
Definition qopenglext.h:487
#define GL_FRAMEBUFFER_COMPLETE
#define GL_MAX_COMPUTE_WORK_GROUP_SIZE
#define GL_VERTEX_PROGRAM_POINT_SIZE
Definition qopenglext.h:582
GLdouble GLdouble t
Definition qopenglext.h:243
#define GL_DRAW_FRAMEBUFFER
#define GL_PROGRAM_BINARY_LENGTH
#define GL_MAX_SAMPLES
#define GL_FUNC_REVERSE_SUBTRACT
Definition qopenglext.h:369
GLuint * samplers
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS
Definition qopenglext.h:185
#define GL_TEXTURE_RECTANGLE
#define GL_TEXTURE_1D_ARRAY
Definition qopenglext.h:922
#define GL_RENDERBUFFER
#define GL_COMPILE_STATUS
Definition qopenglext.h:637
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define GL_MAX_DRAW_BUFFERS
Definition qopenglext.h:588
#define GL_FRAMEBUFFER
GLuint framebuffer
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
#define GL_HALF_FLOAT
GLenum GLenum GLenum GLenum mapping
GLfloat GLfloat p
[1]
#define GL_MAX_ARRAY_TEXTURE_LAYERS
Definition qopenglext.h:916
#define GL_READ_WRITE
Definition qopenglext.h:494
#define GL_CONSTANT_ALPHA
Definition qopenglext.h:366
#define GL_POINT_SPRITE
Definition qopenglext.h:657
#define GL_ONE_MINUS_CONSTANT_COLOR
Definition qopenglext.h:365
#define GL_MAX_VERTEX_UNIFORM_VECTORS
#define GL_DEPTH_STENCIL
#define GL_WRITE_ONLY
Definition qopenglext.h:493
#define GL_READ_FRAMEBUFFER
#define GL_STATIC_DRAW
Definition qopenglext.h:501
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X
Definition qopenglext.h:172
#define GL_MAX_FRAGMENT_UNIFORM_VECTORS
#define GL_DYNAMIC_DRAW
Definition qopenglext.h:504
#define GL_DEPTH_ATTACHMENT
#define GL_SHADER_STORAGE_BARRIER_BIT
#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS
#define GL_VERTEX_SHADER
Definition qopenglext.h:610
#define GL_FUNC_SUBTRACT
Definition qopenglext.h:370
#define GL_ELEMENT_ARRAY_BUFFER
Definition qopenglext.h:488
#define GL_DEPTH_COMPONENT24
Definition qopenglext.h:329
#define GL_PATCH_VERTICES
#define GL_MAX_VERTEX_UNIFORM_COMPONENTS
Definition qopenglext.h:612
#define GL_DECR_WRAP
Definition qopenglext.h:335
#define GL_LINK_STATUS
Definition qopenglext.h:638
#define GL_INFO_LOG_LENGTH
Definition qopenglext.h:640
#define GL_CLAMP_TO_EDGE
Definition qopenglext.h:100
#define GL_INCR_WRAP
Definition qopenglext.h:334
#define GL_STENCIL_ATTACHMENT
#define GL_MAX_VARYING_COMPONENTS
Definition qopenglext.h:921
#define GL_MAX_VARYING_FLOATS
Definition qopenglext.h:613
#define GL_FUNC_ADD
Definition qopenglext.h:368
#define GL_TEXTURE_COMPARE_MODE
Definition qopenglext.h:337
GLsizeiptr const void GLenum usage
Definition qopenglext.h:543
#define GL_READ_ONLY
Definition qopenglext.h:492
static void normalize(double &x, double &y)
#define GL_UNSIGNED_INT_2_10_10_10_REV
#define GL_UNPACK_ROW_LENGTH
void forceUpdate(QQuickItem *item)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QRHI_RES_RHI(t)
Definition qrhi_p.h:29
#define QRHI_RES(t, x)
Definition qrhi_p.h:28
static GLenum toGlMinFilter(QRhiSampler::Filter f, QRhiSampler::Filter m)
static QGles2Buffer::Access toGlAccess(QRhiPassResourceTracker::BufferAccess access)
static GLenum toGlCompressedTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
#define GL_DEPTH_COMPONENT32F
static GLenum toGlTextureCompareFunc(QRhiSampler::CompareOp op)
#define GL_GEOMETRY_SHADER
static GLenum toGlCompareOp(QRhiGraphicsPipeline::CompareOp op)
#define GL_DEPTH24_STENCIL8
#define GL_DEPTH_COMPONENT16
#define GL_R16
static GLenum toGlWrapMode(QRhiSampler::AddressMode m)
static GLenum toGlBlendFactor(QRhiGraphicsPipeline::BlendFactor f)
#define GL_RG16
#define GL_R8
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
#define GL_RGBA8
#define GL_RGBA16F
static GLbitfield barriersForTexture()
#define GL_RG8
#define GL_TESS_CONTROL_SHADER
static GLenum toGlFrontFace(QRhiGraphicsPipeline::FrontFace f)
#define GL_BGRA
\variable QRhiGles2NativeHandles::context
#define GL_UNIFORM_BARRIER_BIT
#define GL_BACK_LEFT
static void addBoundaryCommand(QGles2CommandBuffer *cbD, QGles2CommandBuffer::Command::Cmd type)
#define GL_R32F
#define GL_ELEMENT_ARRAY_BARRIER_BIT
#define GL_TEXTURE_FETCH_BARRIER_BIT
#define GL_UNSIGNED_INT_24_8
#define GL_COMPUTE_SHADER
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QGles2Buffer::UsageState &bufUsage)
static bool bufferAccessIsWrite(QGles2Buffer::Access access)
#define GL_RED
#define GL_RG
#define GL_R16F
static bool isGraphicsStage(const QRhiShaderStage &shaderStage)
#define GL_FILL
static QShader::Stage toShaderStage(QRhiShaderStage::Type type)
#define GL_RGB10_A2
static GLenum toGlBlendOp(QRhiGraphicsPipeline::BlendOp op)
#define GL_HALF_FLOAT
#define GL_TESS_EVALUATION_SHADER
#define GL_PIXEL_BUFFER_BARRIER_BIT
static void toGlTextureFormat(QRhiTexture::Format format, const QRhiGles2::Caps &caps, GLenum *glintformat, GLenum *glsizedintformat, GLenum *glformat, GLenum *gltype)
#define GL_DEPTH_STENCIL
#define GL_TEXTURE_UPDATE_BARRIER_BIT
static GLenum toGlShaderType(QRhiShaderStage::Type type)
#define GL_BUFFER_UPDATE_BARRIER_BIT
static GLenum toGlCullMode(QRhiGraphicsPipeline::CullMode c)
#define GL_LINE
static GLenum toGlStencilOp(QRhiGraphicsPipeline::StencilOp op)
static GLbitfield barriersForBuffer()
static GLenum toGlTopology(QRhiGraphicsPipeline::Topology t)
#define GL_SHADER_STORAGE_BARRIER_BIT
#define GL_RGBA32F
void qrhigl_accumulateComputeResource(T *writtenResources, QRhiResource *resource, QRhiShaderResourceBinding::Type bindingType, int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
static void bindVertexIndexBufferWithStateReset(CommandBufferExecTrackedState *state, QOpenGLExtensions *f, GLenum target, GLuint buffer)
#define GL_DEPTH_COMPONENT24
static bool textureAccessIsWrite(QGles2Texture::Access access)
#define GL_TEXTURE_1D
static GLenum toGlMagFilter(QRhiSampler::Filter f)
#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT
#define GL_FRAMEBUFFER_BARRIER_BIT
static void qrhi_std140_to_packed(T *dst, int vecSize, int elemCount, const void *src)
#define GL_UNSIGNED_INT_2_10_10_10_REV
#define GL_PATCHES
#define GL_STENCIL_INDEX
static GLenum toGlPolygonMode(QRhiGraphicsPipeline::PolygonMode mode)
static QSurface * currentSurfaceForCurrentContext(QOpenGLContext *ctx)
#define GL_BACK_RIGHT
#define GLuint
#define GL_FLOAT
#define GL_UNSIGNED_BYTE
#define GL_RGBA
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define sp
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
@ desc
unsigned int quint32
Definition qtypes.h:45
unsigned short quint16
Definition qtypes.h:43
size_t quintptr
Definition qtypes.h:72
int qint32
Definition qtypes.h:44
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
unsigned char quint8
Definition qtypes.h:41
QVideoFrameFormat::PixelFormat fmt
QStorageInfo storage
[1]
QSharedPointer< T > other(t)
[5]
view viewport() -> scroll(dx, dy, deviceRect)
QSvgRenderer * renderer
[0]
struct CommandBufferExecTrackedState::@353 lastBindVertexBuffer
bool nonzeroAttribDivisor[TRACKED_ATTRIB_COUNT]
static const int TRACKED_ATTRIB_COUNT
QRhiGraphicsPipeline * ps
bool enabledAttribArrays[TRACKED_ATTRIB_COUNT]
QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
@ AccessStorageReadWrite
Definition qrhigles2_p.h:52
QByteArray data
Definition qrhigles2_p.h:44
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
char * beginFullDynamicBufferUpdateForCurrentFrame() override
void endFullDynamicBufferUpdateForCurrentFrame() override
To be called when the entire contents of the buffer data has been updated in the memory block returne...
QRhiBuffer::NativeBuffer nativeBuffer() override
bool create() override
Creates the corresponding native graphics resources.
GLenum targetForDataOps
Definition qrhigles2_p.h:43
quint32 nonZeroSize
Definition qrhigles2_p.h:41
UsageState usageState
Definition qrhigles2_p.h:58
GLuint buffer
Definition qrhigles2_p.h:42
union QGles2CommandBuffer::Command::Args args
QHash< QRhiResource *, QPair< int, bool > > writtenResources
struct QGles2CommandBuffer::GraphicsPassState::@357 dynamic
struct QGles2CommandBuffer::ComputePassState computePassState
QRhiShaderResourceBindings * currentGraphicsSrb
static const int MAX_DYNAMIC_OFFSET_COUNT
struct QGles2CommandBuffer::GraphicsPassState graphicsPassState
QRhiBackendCommandList< Command > commands
QRhiComputePipeline * currentComputePipeline
QRhiRenderTarget * currentTarget
QRhiShaderResourceBindings * currentComputeSrb
QVarLengthArray< QRhiPassResourceTracker, 8 > passResTrackers
QGles2CommandBuffer(QRhiImplementation *rhi)
const void * retainImage(const QImage &image)
const void * retainData(const QByteArray &data)
const uchar * retainBufferData(const QRhiBufferData &data)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
struct QGles2CommandBuffer::TextureUnitState textureUnitState[16]
QRhiGraphicsPipeline * currentGraphicsPipeline
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION+1]
QGles2UniformDescriptionVector uniforms
QRhiShaderResourceBindings * currentSrb
QGles2ComputePipeline(QRhiImplementation *rhi)
bool create() override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool create() override
Creates the corresponding native graphics resources.
QGles2GraphicsPipeline(QRhiImplementation *rhi)
QRhiShaderResourceBindings * currentSrb
QGles2UniformDescriptionVector uniforms
QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION+1]
bool create() override
Creates the corresponding native graphics resources.
QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags, QRhiTexture::Format backingFormatHint)
bool createFrom(NativeRenderBuffer src) override
Similar to create() except that no new native renderbuffer objects are created.
QRhiTexture::Format backingFormat() const override
GLuint stencilRenderbuffer
Definition qrhigles2_p.h:74
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVector< quint32 > serializedFormat() const override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() const override
bool isCompatible(const QRhiRenderPassDescriptor *other) const override
QGles2RenderPassDescriptor(QRhiImplementation *rhi)
std::optional< QRhiSwapChain::StereoTargetBuffer > stereoTarget
QGles2RenderPassDescriptor * rp
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList
GLenum gltexcomparefunc
Definition qrhigles2_p.h:88
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool create() override
QGles2SamplerData d
QGles2Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v, AddressMode w)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
void updateResources(UpdateFlags flags) override
QGles2ShaderResourceBindings(QRhiImplementation *rhi)
float devicePixelRatio() const override
QGles2SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
QSize pixelSize() const override
int sampleCount() const override
QGles2RenderTargetData d
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
void initSwapChainRenderTarget(QGles2SwapChainRenderTarget *rt)
QGles2SwapChainRenderTarget rtRight
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QGles2CommandBuffer cb
QGles2SwapChainRenderTarget rt
QSurface * surface
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
bool isFormatSupported(Format f) override
bool createOrResize() override
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
QGles2SwapChain(QRhiImplementation *rhi)
QRhiCommandBuffer * currentFrameCommandBuffer() override
QGles2SwapChainRenderTarget rtLeft
QSize surfacePixelSize() override
QRhiRenderTarget * currentFrameRenderTarget() override
int sampleCount() const override
QGles2TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
float devicePixelRatio() const override
QSize pixelSize() const override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
bool create() override
Creates the corresponding native graphics resources.
QGles2RenderTargetData d
bool createFrom(NativeTexture src) override
Similar to create(), except that no new native textures are created.
QGles2Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, Flags flags)
QGles2SamplerData samplerState
GLenum glsizedintformat
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
UsageState usageState
bool prepareCreate(QSize *adjustedSize=nullptr)
GLenum glintformat
bool create() override
Creates the corresponding native graphics resources.
NativeTexture nativeTexture() override
QShaderDescription::VariableType type
static constexpr int MAX_TRACKED_LOCATION
\inmodule QtGui
Definition qrhi.h:850
\inmodule QtGui
Definition qrhi.h:1722
QByteArray deviceName
Definition qrhi.h:1732
uint needsDepthStencilCombinedAttach
uint srgbCapableDefaultFramebuffer
int maxThreadGroupsPerDimension
uint fixedIndexPrimitiveRestart
uint screenSpaceDerivatives
uint nonBaseLevelFramebufferTexture
int maxThreadsPerThreadGroup
QGles2CommandBuffer cbWrapper
\variable QRhiReadbackResult::completed
Definition qrhi.h:788
\inmodule QtGui
Definition qrhi.h:1686
QByteArray data
Definition qrhi.h:1690
std::function< void()> completed
Definition qrhi.h:1687
QRhiTextureCopyDescription desc
Definition qrhi_p.h:458
QVarLengthArray< MipLevelUploadList, 6 > subresDesc
Definition qrhi_p.h:456
\inmodule QtGui
Definition qrhi.h:1745
\inmodule QtGui
Definition qrhi.h:953
\variable QShaderDescription::InOutVariable::name
\variable QShaderDescription::BlockVariable::name
Definition moc.h:24
struct QGles2CommandBuffer::Command::Args::@261 stencilRef
struct QGles2CommandBuffer::Command::Args::@290 compressedSubImage
struct QGles2CommandBuffer::Command::Args::@288 compressedImage
struct QGles2CommandBuffer::Command::Args::@305 barriersForPass
struct QGles2CommandBuffer::Command::Args::@268 bindShaderResources
struct QGles2CommandBuffer::Command::Args::@296 blitFromTexture
struct QGles2CommandBuffer::Command::Args::@300 bindComputePipeline
struct QGles2CommandBuffer::Command::Args::@260 blendConstants
struct QGles2CommandBuffer::Command::Args::@302 dispatch
struct QGles2CommandBuffer::Command::Args::@270 clear
struct QGles2CommandBuffer::Command::Args::@281 readPixels
struct QGles2CommandBuffer::Command::Args::@259 scissor
struct QGles2CommandBuffer::Command::Args::@298 genMip
struct QGles2CommandBuffer::Command::Args::@263 bindIndexBuffer
struct QGles2CommandBuffer::Command::Args::@285 subImage
uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT *2]
QRhiShaderResourceBindings * srb
struct QGles2CommandBuffer::Command::Args::@273 bindFramebuffer
struct QGles2CommandBuffer::Command::Args::@276 getBufferSubData
QRhiGraphicsPipeline * maybeGraphicsPs
struct QGles2CommandBuffer::Command::Args::@264 draw
struct QGles2CommandBuffer::Command::Args::@275 bufferSubData
struct QGles2CommandBuffer::Command::Args::@279 copyTex
struct QGles2CommandBuffer::Command::Args::@306 barrier
struct QGles2CommandBuffer::Command::Args::@258 viewport
struct QGles2CommandBuffer::Command::Args::@265 drawIndexed
QRhiComputePipeline * maybeComputePs
QRhiSwapChain::StereoTargetBuffer stereoTarget
struct QGles2CommandBuffer::Command::Args::@266 bindGraphicsPipeline
struct QGles2CommandBuffer::Command::Args::@292 blitFromRenderbuffer
struct QGles2CommandBuffer::Command::Args::@262 bindVertexBuffer