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 | #ifndef QRHIGLES2_P_H |
5 | #define QRHIGLES2_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "qrhi_p.h" |
19 | #include <rhi/qshaderdescription.h> |
20 | #include <qopengl.h> |
21 | #include <QByteArray> |
22 | #include <QWindow> |
23 | #include <QPointer> |
24 | #include <QtCore/private/qduplicatetracker_p.h> |
25 | #include <optional> |
26 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | class QOpenGLExtensions; |
30 | |
31 | struct QGles2Buffer : public QRhiBuffer |
32 | { |
33 | QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size); |
34 | ~QGles2Buffer(); |
35 | void destroy() override; |
36 | bool create() override; |
37 | QRhiBuffer::NativeBuffer nativeBuffer() override; |
38 | char *beginFullDynamicBufferUpdateForCurrentFrame() override; |
39 | void endFullDynamicBufferUpdateForCurrentFrame() override; |
40 | |
41 | quint32 nonZeroSize = 0; |
42 | GLuint buffer = 0; |
43 | GLenum targetForDataOps; |
44 | QByteArray data; |
45 | enum Access { |
46 | AccessNone, |
47 | AccessVertex, |
48 | AccessIndex, |
49 | AccessUniform, |
50 | AccessStorageRead, |
51 | AccessStorageWrite, |
52 | AccessStorageReadWrite, |
53 | AccessUpdate |
54 | }; |
55 | struct UsageState { |
56 | Access access; |
57 | }; |
58 | UsageState usageState; |
59 | friend class QRhiGles2; |
60 | }; |
61 | |
62 | struct QGles2RenderBuffer : public QRhiRenderBuffer |
63 | { |
64 | QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, |
65 | int sampleCount, QRhiRenderBuffer::Flags flags, |
66 | QRhiTexture::Format backingFormatHint); |
67 | ~QGles2RenderBuffer(); |
68 | void destroy() override; |
69 | bool create() override; |
70 | bool createFrom(NativeRenderBuffer src) override; |
71 | QRhiTexture::Format backingFormat() const override; |
72 | |
73 | GLuint renderbuffer = 0; |
74 | GLuint stencilRenderbuffer = 0; // when packed depth-stencil not supported |
75 | int samples; |
76 | bool owns = true; |
77 | uint generation = 0; |
78 | friend class QRhiGles2; |
79 | }; |
80 | |
81 | struct QGles2SamplerData |
82 | { |
83 | GLenum glminfilter = 0; |
84 | GLenum glmagfilter = 0; |
85 | GLenum glwraps = 0; |
86 | GLenum glwrapt = 0; |
87 | GLenum glwrapr = 0; |
88 | GLenum gltexcomparefunc = 0; |
89 | }; |
90 | |
91 | inline bool operator==(const QGles2SamplerData &a, const QGles2SamplerData &b) |
92 | { |
93 | return a.glminfilter == b.glminfilter |
94 | && a.glmagfilter == b.glmagfilter |
95 | && a.glwraps == b.glwraps |
96 | && a.glwrapt == b.glwrapt |
97 | && a.glwrapr == b.glwrapr |
98 | && a.gltexcomparefunc == b.gltexcomparefunc; |
99 | } |
100 | |
101 | inline bool operator!=(const QGles2SamplerData &a, const QGles2SamplerData &b) |
102 | { |
103 | return !(a == b); |
104 | } |
105 | |
106 | struct QGles2Texture : public QRhiTexture |
107 | { |
108 | QGles2Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, |
109 | int arraySize, int sampleCount, Flags flags); |
110 | ~QGles2Texture(); |
111 | void destroy() override; |
112 | bool create() override; |
113 | bool createFrom(NativeTexture src) override; |
114 | NativeTexture nativeTexture() override; |
115 | |
116 | bool prepareCreate(QSize *adjustedSize = nullptr); |
117 | |
118 | GLuint texture = 0; |
119 | bool owns = true; |
120 | GLenum target; |
121 | GLenum glintformat; |
122 | GLenum glsizedintformat; |
123 | GLenum glformat; |
124 | GLenum gltype; |
125 | QGles2SamplerData samplerState; |
126 | bool specified = false; |
127 | bool zeroInitialized = false; |
128 | int mipLevelCount = 0; |
129 | |
130 | enum Access { |
131 | AccessNone, |
132 | AccessSample, |
133 | AccessFramebuffer, |
134 | AccessStorageRead, |
135 | AccessStorageWrite, |
136 | AccessStorageReadWrite, |
137 | AccessUpdate, |
138 | AccessRead |
139 | }; |
140 | struct UsageState { |
141 | Access access; |
142 | }; |
143 | UsageState usageState; |
144 | |
145 | uint generation = 0; |
146 | friend class QRhiGles2; |
147 | }; |
148 | |
149 | struct QGles2Sampler : public QRhiSampler |
150 | { |
151 | QGles2Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, |
152 | AddressMode u, AddressMode v, AddressMode w); |
153 | ~QGles2Sampler(); |
154 | void destroy() override; |
155 | bool create() override; |
156 | |
157 | QGles2SamplerData d; |
158 | uint generation = 0; |
159 | friend class QRhiGles2; |
160 | }; |
161 | |
162 | struct QGles2RenderPassDescriptor : public QRhiRenderPassDescriptor |
163 | { |
164 | QGles2RenderPassDescriptor(QRhiImplementation *rhi); |
165 | ~QGles2RenderPassDescriptor(); |
166 | void destroy() override; |
167 | bool isCompatible(const QRhiRenderPassDescriptor *other) const override; |
168 | QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override; |
169 | QVector<quint32> serializedFormat() const override; |
170 | }; |
171 | |
172 | struct QGles2RenderTargetData |
173 | { |
174 | QGles2RenderTargetData(QRhiImplementation *) { } |
175 | |
176 | bool isValid() const { return rp != nullptr; } |
177 | |
178 | QGles2RenderPassDescriptor *rp = nullptr; |
179 | QSize pixelSize; |
180 | float dpr = 1; |
181 | int sampleCount = 1; |
182 | int colorAttCount = 0; |
183 | int dsAttCount = 0; |
184 | bool srgbUpdateAndBlend = false; |
185 | QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList; |
186 | std::optional<QRhiSwapChain::StereoTargetBuffer> stereoTarget; |
187 | }; |
188 | |
189 | struct QGles2SwapChainRenderTarget : public QRhiSwapChainRenderTarget |
190 | { |
191 | QGles2SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain); |
192 | ~QGles2SwapChainRenderTarget(); |
193 | void destroy() override; |
194 | |
195 | QSize pixelSize() const override; |
196 | float devicePixelRatio() const override; |
197 | int sampleCount() const override; |
198 | |
199 | QGles2RenderTargetData d; |
200 | }; |
201 | |
202 | struct QGles2TextureRenderTarget : public QRhiTextureRenderTarget |
203 | { |
204 | QGles2TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags); |
205 | ~QGles2TextureRenderTarget(); |
206 | void destroy() override; |
207 | |
208 | QSize pixelSize() const override; |
209 | float devicePixelRatio() const override; |
210 | int sampleCount() const override; |
211 | |
212 | QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override; |
213 | bool create() override; |
214 | |
215 | QGles2RenderTargetData d; |
216 | GLuint framebuffer = 0; |
217 | friend class QRhiGles2; |
218 | }; |
219 | |
220 | struct QGles2ShaderResourceBindings : public QRhiShaderResourceBindings |
221 | { |
222 | QGles2ShaderResourceBindings(QRhiImplementation *rhi); |
223 | ~QGles2ShaderResourceBindings(); |
224 | void destroy() override; |
225 | bool create() override; |
226 | void updateResources(UpdateFlags flags) override; |
227 | |
228 | bool hasDynamicOffset = false; |
229 | uint generation = 0; |
230 | friend class QRhiGles2; |
231 | }; |
232 | |
233 | struct QGles2UniformDescription |
234 | { |
235 | QShaderDescription::VariableType type; |
236 | int glslLocation; |
237 | int binding; |
238 | quint32 offset; |
239 | quint32 size; |
240 | int arrayDim; |
241 | }; |
242 | |
243 | Q_DECLARE_TYPEINFO(QGles2UniformDescription, Q_RELOCATABLE_TYPE); |
244 | |
245 | struct QGles2SamplerDescription |
246 | { |
247 | int glslLocation; |
248 | int combinedBinding; |
249 | int tbinding; |
250 | int sbinding; |
251 | }; |
252 | |
253 | Q_DECLARE_TYPEINFO(QGles2SamplerDescription, Q_RELOCATABLE_TYPE); |
254 | |
255 | using QGles2UniformDescriptionVector = QVarLengthArray<QGles2UniformDescription, 8>; |
256 | using QGles2SamplerDescriptionVector = QVarLengthArray<QGles2SamplerDescription, 4>; |
257 | |
258 | struct QGles2UniformState |
259 | { |
260 | static constexpr int MAX_TRACKED_LOCATION = 1023; |
261 | int componentCount; |
262 | float v[4]; |
263 | }; |
264 | |
265 | struct QGles2GraphicsPipeline : public QRhiGraphicsPipeline |
266 | { |
267 | QGles2GraphicsPipeline(QRhiImplementation *rhi); |
268 | ~QGles2GraphicsPipeline(); |
269 | void destroy() override; |
270 | bool create() override; |
271 | |
272 | GLuint program = 0; |
273 | GLenum drawMode = GL_TRIANGLES; |
274 | QGles2UniformDescriptionVector uniforms; |
275 | QGles2SamplerDescriptionVector samplers; |
276 | QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION + 1]; |
277 | QRhiShaderResourceBindings *currentSrb = nullptr; |
278 | uint currentSrbGeneration = 0; |
279 | uint generation = 0; |
280 | friend class QRhiGles2; |
281 | }; |
282 | |
283 | struct QGles2ComputePipeline : public QRhiComputePipeline |
284 | { |
285 | QGles2ComputePipeline(QRhiImplementation *rhi); |
286 | ~QGles2ComputePipeline(); |
287 | void destroy() override; |
288 | bool create() override; |
289 | |
290 | GLuint program = 0; |
291 | QGles2UniformDescriptionVector uniforms; |
292 | QGles2SamplerDescriptionVector samplers; |
293 | QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION + 1]; |
294 | QRhiShaderResourceBindings *currentSrb = nullptr; |
295 | uint currentSrbGeneration = 0; |
296 | uint generation = 0; |
297 | friend class QRhiGles2; |
298 | }; |
299 | |
300 | struct QGles2CommandBuffer : public QRhiCommandBuffer |
301 | { |
302 | QGles2CommandBuffer(QRhiImplementation *rhi); |
303 | ~QGles2CommandBuffer(); |
304 | void destroy() override; |
305 | |
306 | // keep at a reasonably low value otherwise sizeof Command explodes |
307 | static const int MAX_DYNAMIC_OFFSET_COUNT = 8; |
308 | |
309 | struct Command { |
310 | enum Cmd { |
311 | BeginFrame, |
312 | EndFrame, |
313 | ResetFrame, |
314 | Viewport, |
315 | Scissor, |
316 | BlendConstants, |
317 | StencilRef, |
318 | BindVertexBuffer, |
319 | BindIndexBuffer, |
320 | Draw, |
321 | DrawIndexed, |
322 | BindGraphicsPipeline, |
323 | BindShaderResources, |
324 | BindFramebuffer, |
325 | Clear, |
326 | BufferSubData, |
327 | GetBufferSubData, |
328 | CopyTex, |
329 | ReadPixels, |
330 | SubImage, |
331 | CompressedImage, |
332 | CompressedSubImage, |
333 | BlitFromRenderbuffer, |
334 | BlitFromTexture, |
335 | GenMip, |
336 | BindComputePipeline, |
337 | Dispatch, |
338 | BarriersForPass, |
339 | Barrier |
340 | }; |
341 | Cmd cmd; |
342 | |
343 | // QRhi*/QGles2* references should be kept at minimum (so no |
344 | // QRhiTexture/Buffer/etc. pointers). |
345 | union Args { |
346 | struct { |
347 | float x, y, w, h; |
348 | float d0, d1; |
349 | } viewport; |
350 | struct { |
351 | int x, y, w, h; |
352 | } scissor; |
353 | struct { |
354 | float r, g, b, a; |
355 | } blendConstants; |
356 | struct { |
357 | quint32 ref; |
358 | QRhiGraphicsPipeline *ps; |
359 | } stencilRef; |
360 | struct { |
361 | QRhiGraphicsPipeline *ps; |
362 | GLuint buffer; |
363 | quint32 offset; |
364 | int binding; |
365 | } bindVertexBuffer; |
366 | struct { |
367 | GLuint buffer; |
368 | quint32 offset; |
369 | GLenum type; |
370 | } bindIndexBuffer; |
371 | struct { |
372 | QRhiGraphicsPipeline *ps; |
373 | quint32 vertexCount; |
374 | quint32 firstVertex; |
375 | quint32 instanceCount; |
376 | quint32 baseInstance; |
377 | } draw; |
378 | struct { |
379 | QRhiGraphicsPipeline *ps; |
380 | quint32 indexCount; |
381 | quint32 firstIndex; |
382 | quint32 instanceCount; |
383 | quint32 baseInstance; |
384 | qint32 baseVertex; |
385 | } drawIndexed; |
386 | struct { |
387 | QRhiGraphicsPipeline *ps; |
388 | } bindGraphicsPipeline; |
389 | struct { |
390 | QRhiGraphicsPipeline *maybeGraphicsPs; |
391 | QRhiComputePipeline *maybeComputePs; |
392 | QRhiShaderResourceBindings *srb; |
393 | int dynamicOffsetCount; |
394 | uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT * 2]; // binding, offset |
395 | } bindShaderResources; |
396 | struct { |
397 | GLbitfield mask; |
398 | float c[4]; |
399 | float d; |
400 | quint32 s; |
401 | } clear; |
402 | struct { |
403 | GLuint fbo; |
404 | bool srgb; |
405 | int colorAttCount; |
406 | bool stereo; |
407 | QRhiSwapChain::StereoTargetBuffer stereoTarget; |
408 | } bindFramebuffer; |
409 | struct { |
410 | GLenum target; |
411 | GLuint buffer; |
412 | int offset; |
413 | int size; |
414 | const void *data; // must come from retainData() |
415 | } bufferSubData; |
416 | struct { |
417 | QRhiReadbackResult *result; |
418 | GLenum target; |
419 | GLuint buffer; |
420 | int offset; |
421 | int size; |
422 | } getBufferSubData; |
423 | struct { |
424 | GLenum srcTarget; |
425 | GLenum srcFaceTarget; |
426 | GLuint srcTexture; |
427 | int srcLevel; |
428 | int srcX; |
429 | int srcY; |
430 | int srcZ; |
431 | GLenum dstTarget; |
432 | GLuint dstTexture; |
433 | GLenum dstFaceTarget; |
434 | int dstLevel; |
435 | int dstX; |
436 | int dstY; |
437 | int dstZ; |
438 | int w; |
439 | int h; |
440 | } copyTex; |
441 | struct { |
442 | QRhiReadbackResult *result; |
443 | GLuint texture; |
444 | int w; |
445 | int h; |
446 | QRhiTexture::Format format; |
447 | GLenum readTarget; |
448 | int level; |
449 | int slice3D; |
450 | } readPixels; |
451 | struct { |
452 | GLenum target; |
453 | GLuint texture; |
454 | GLenum faceTarget; |
455 | int level; |
456 | int dx; |
457 | int dy; |
458 | int dz; |
459 | int w; |
460 | int h; |
461 | GLenum glformat; |
462 | GLenum gltype; |
463 | int rowStartAlign; |
464 | int rowLength; |
465 | const void *data; // must come from retainImage() |
466 | } subImage; |
467 | struct { |
468 | GLenum target; |
469 | GLuint texture; |
470 | GLenum faceTarget; |
471 | int level; |
472 | GLenum glintformat; |
473 | int w; |
474 | int h; |
475 | int depth; |
476 | int size; |
477 | const void *data; // must come from retainData() |
478 | } compressedImage; |
479 | struct { |
480 | GLenum target; |
481 | GLuint texture; |
482 | GLenum faceTarget; |
483 | int level; |
484 | int dx; |
485 | int dy; |
486 | int dz; |
487 | int w; |
488 | int h; |
489 | GLenum glintformat; |
490 | int size; |
491 | const void *data; // must come from retainData() |
492 | } compressedSubImage; |
493 | struct { |
494 | GLuint renderbuffer; |
495 | int w; |
496 | int h; |
497 | GLenum target; |
498 | GLuint dstTexture; |
499 | int dstLevel; |
500 | int dstLayer; |
501 | } blitFromRenderbuffer; |
502 | struct { |
503 | GLenum srcTarget; |
504 | GLuint srcTexture; |
505 | int srcLevel; |
506 | int srcLayer; |
507 | int w; |
508 | int h; |
509 | GLenum dstTarget; |
510 | GLuint dstTexture; |
511 | int dstLevel; |
512 | int dstLayer; |
513 | } blitFromTexture; |
514 | struct { |
515 | GLenum target; |
516 | GLuint texture; |
517 | } genMip; |
518 | struct { |
519 | QRhiComputePipeline *ps; |
520 | } bindComputePipeline; |
521 | struct { |
522 | GLuint x; |
523 | GLuint y; |
524 | GLuint z; |
525 | } dispatch; |
526 | struct { |
527 | int trackerIndex; |
528 | } barriersForPass; |
529 | struct { |
530 | GLbitfield barriers; |
531 | } barrier; |
532 | } args; |
533 | }; |
534 | |
535 | enum PassType { |
536 | NoPass, |
537 | RenderPass, |
538 | ComputePass |
539 | }; |
540 | |
541 | QRhiBackendCommandList<Command> commands; |
542 | QVarLengthArray<QRhiPassResourceTracker, 8> passResTrackers; |
543 | int currentPassResTrackerIndex; |
544 | |
545 | PassType recordingPass; |
546 | bool passNeedsResourceTracking; |
547 | QRhiRenderTarget *currentTarget; |
548 | QRhiGraphicsPipeline *currentGraphicsPipeline; |
549 | QRhiComputePipeline *currentComputePipeline; |
550 | uint currentPipelineGeneration; |
551 | QRhiShaderResourceBindings *currentGraphicsSrb; |
552 | QRhiShaderResourceBindings *currentComputeSrb; |
553 | uint currentSrbGeneration; |
554 | |
555 | struct GraphicsPassState { |
556 | bool valid = false; |
557 | bool scissor; |
558 | bool cullFace; |
559 | GLenum cullMode; |
560 | GLenum frontFace; |
561 | bool blendEnabled; |
562 | struct ColorMask { bool r, g, b, a; } colorMask; |
563 | struct Blend { |
564 | GLenum srcColor; |
565 | GLenum dstColor; |
566 | GLenum srcAlpha; |
567 | GLenum dstAlpha; |
568 | GLenum opColor; |
569 | GLenum opAlpha; |
570 | } blend; |
571 | bool depthTest; |
572 | bool depthWrite; |
573 | GLenum depthFunc; |
574 | bool stencilTest; |
575 | GLuint stencilReadMask; |
576 | GLuint stencilWriteMask; |
577 | struct StencilFace { |
578 | GLenum func; |
579 | GLenum failOp; |
580 | GLenum zfailOp; |
581 | GLenum zpassOp; |
582 | } stencil[2]; // front, back |
583 | bool polyOffsetFill; |
584 | float polyOffsetFactor; |
585 | float polyOffsetUnits; |
586 | float lineWidth; |
587 | int cpCount; |
588 | GLenum polygonMode; |
589 | void reset() { valid = false; } |
590 | struct { |
591 | // not part of QRhiGraphicsPipeline but used by setGraphicsPipeline() |
592 | GLint stencilRef = 0; |
593 | } dynamic; |
594 | } graphicsPassState; |
595 | |
596 | struct ComputePassState { |
597 | enum Access { |
598 | Read = 0x01, |
599 | Write = 0x02 |
600 | }; |
601 | QHash<QRhiResource *, QPair<int, bool> > writtenResources; |
602 | void reset() { |
603 | writtenResources.clear(); |
604 | } |
605 | } computePassState; |
606 | |
607 | struct TextureUnitState { |
608 | void *ps; |
609 | uint psGeneration; |
610 | uint texture; |
611 | } textureUnitState[16]; |
612 | |
613 | QVarLengthArray<QByteArray, 4> dataRetainPool; |
614 | QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool; |
615 | QVarLengthArray<QImage, 4> imageRetainPool; |
616 | |
617 | // relies heavily on implicit sharing (no copies of the actual data will be made) |
618 | const void *retainData(const QByteArray &data) { |
619 | dataRetainPool.append(t: data); |
620 | return dataRetainPool.last().constData(); |
621 | } |
622 | const uchar *retainBufferData(const QRhiBufferData &data) { |
623 | bufferDataRetainPool.append(t: data); |
624 | return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData()); |
625 | } |
626 | const void *retainImage(const QImage &image) { |
627 | imageRetainPool.append(t: image); |
628 | return imageRetainPool.last().constBits(); |
629 | } |
630 | void resetCommands() { |
631 | commands.reset(); |
632 | dataRetainPool.clear(); |
633 | bufferDataRetainPool.clear(); |
634 | imageRetainPool.clear(); |
635 | |
636 | passResTrackers.clear(); |
637 | currentPassResTrackerIndex = -1; |
638 | } |
639 | void resetState() { |
640 | recordingPass = NoPass; |
641 | passNeedsResourceTracking = true; |
642 | currentTarget = nullptr; |
643 | resetCommands(); |
644 | resetCachedState(); |
645 | } |
646 | void resetCachedState() { |
647 | currentGraphicsPipeline = nullptr; |
648 | currentComputePipeline = nullptr; |
649 | currentPipelineGeneration = 0; |
650 | currentGraphicsSrb = nullptr; |
651 | currentComputeSrb = nullptr; |
652 | currentSrbGeneration = 0; |
653 | graphicsPassState.reset(); |
654 | computePassState.reset(); |
655 | memset(s: textureUnitState, c: 0, n: sizeof(textureUnitState)); |
656 | } |
657 | }; |
658 | |
659 | inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a, |
660 | const QGles2CommandBuffer::GraphicsPassState::StencilFace &b) |
661 | { |
662 | return a.func == b.func |
663 | && a.failOp == b.failOp |
664 | && a.zfailOp == b.zfailOp |
665 | && a.zpassOp == b.zpassOp; |
666 | } |
667 | |
668 | inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a, |
669 | const QGles2CommandBuffer::GraphicsPassState::StencilFace &b) |
670 | { |
671 | return !(a == b); |
672 | } |
673 | |
674 | inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a, |
675 | const QGles2CommandBuffer::GraphicsPassState::ColorMask &b) |
676 | { |
677 | return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; |
678 | } |
679 | |
680 | inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a, |
681 | const QGles2CommandBuffer::GraphicsPassState::ColorMask &b) |
682 | { |
683 | return !(a == b); |
684 | } |
685 | |
686 | inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::Blend &a, |
687 | const QGles2CommandBuffer::GraphicsPassState::Blend &b) |
688 | { |
689 | return a.srcColor == b.srcColor |
690 | && a.dstColor == b.dstColor |
691 | && a.srcAlpha == b.srcAlpha |
692 | && a.dstAlpha == b.dstAlpha |
693 | && a.opColor == b.opColor |
694 | && a.opAlpha == b.opAlpha; |
695 | } |
696 | |
697 | inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::Blend &a, |
698 | const QGles2CommandBuffer::GraphicsPassState::Blend &b) |
699 | { |
700 | return !(a == b); |
701 | } |
702 | |
703 | struct QGles2SwapChain : public QRhiSwapChain |
704 | { |
705 | QGles2SwapChain(QRhiImplementation *rhi); |
706 | ~QGles2SwapChain(); |
707 | void destroy() override; |
708 | |
709 | QRhiCommandBuffer *currentFrameCommandBuffer() override; |
710 | QRhiRenderTarget *currentFrameRenderTarget() override; |
711 | QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override; |
712 | |
713 | QSize surfacePixelSize() override; |
714 | bool isFormatSupported(Format f) override; |
715 | |
716 | QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override; |
717 | bool createOrResize() override; |
718 | |
719 | void initSwapChainRenderTarget(QGles2SwapChainRenderTarget *rt); |
720 | |
721 | QSurface *surface = nullptr; |
722 | QSize pixelSize; |
723 | QGles2SwapChainRenderTarget rt; |
724 | QGles2SwapChainRenderTarget rtLeft; |
725 | QGles2SwapChainRenderTarget rtRight; |
726 | QGles2CommandBuffer cb; |
727 | int frameCount = 0; |
728 | }; |
729 | |
730 | class QRhiGles2 : public QRhiImplementation |
731 | { |
732 | public: |
733 | QRhiGles2(QRhiGles2InitParams *params, QRhiGles2NativeHandles *importDevice = nullptr); |
734 | |
735 | bool create(QRhi::Flags flags) override; |
736 | void destroy() override; |
737 | |
738 | QRhiGraphicsPipeline *createGraphicsPipeline() override; |
739 | QRhiComputePipeline *createComputePipeline() override; |
740 | QRhiShaderResourceBindings *createShaderResourceBindings() override; |
741 | QRhiBuffer *createBuffer(QRhiBuffer::Type type, |
742 | QRhiBuffer::UsageFlags usage, |
743 | quint32 size) override; |
744 | QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, |
745 | const QSize &pixelSize, |
746 | int sampleCount, |
747 | QRhiRenderBuffer::Flags flags, |
748 | QRhiTexture::Format backingFormatHint) override; |
749 | QRhiTexture *createTexture(QRhiTexture::Format format, |
750 | const QSize &pixelSize, |
751 | int depth, |
752 | int arraySize, |
753 | int sampleCount, |
754 | QRhiTexture::Flags flags) override; |
755 | QRhiSampler *createSampler(QRhiSampler::Filter magFilter, |
756 | QRhiSampler::Filter minFilter, |
757 | QRhiSampler::Filter mipmapMode, |
758 | QRhiSampler:: AddressMode u, |
759 | QRhiSampler::AddressMode v, |
760 | QRhiSampler::AddressMode w) override; |
761 | |
762 | QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, |
763 | QRhiTextureRenderTarget::Flags flags) override; |
764 | |
765 | QRhiSwapChain *createSwapChain() override; |
766 | QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override; |
767 | QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override; |
768 | QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override; |
769 | QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override; |
770 | QRhi::FrameOpResult finish() override; |
771 | |
772 | void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override; |
773 | |
774 | void beginPass(QRhiCommandBuffer *cb, |
775 | QRhiRenderTarget *rt, |
776 | const QColor &colorClearValue, |
777 | const QRhiDepthStencilClearValue &depthStencilClearValue, |
778 | QRhiResourceUpdateBatch *resourceUpdates, |
779 | QRhiCommandBuffer::BeginPassFlags flags) override; |
780 | void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override; |
781 | |
782 | void setGraphicsPipeline(QRhiCommandBuffer *cb, |
783 | QRhiGraphicsPipeline *ps) override; |
784 | |
785 | void setShaderResources(QRhiCommandBuffer *cb, |
786 | QRhiShaderResourceBindings *srb, |
787 | int dynamicOffsetCount, |
788 | const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override; |
789 | |
790 | void setVertexInput(QRhiCommandBuffer *cb, |
791 | int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, |
792 | QRhiBuffer *indexBuf, quint32 indexOffset, |
793 | QRhiCommandBuffer::IndexFormat indexFormat) override; |
794 | |
795 | void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override; |
796 | void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override; |
797 | void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override; |
798 | void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override; |
799 | |
800 | void draw(QRhiCommandBuffer *cb, quint32 vertexCount, |
801 | quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override; |
802 | |
803 | void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, |
804 | quint32 instanceCount, quint32 firstIndex, |
805 | qint32 vertexOffset, quint32 firstInstance) override; |
806 | |
807 | void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override; |
808 | void debugMarkEnd(QRhiCommandBuffer *cb) override; |
809 | void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override; |
810 | |
811 | void beginComputePass(QRhiCommandBuffer *cb, |
812 | QRhiResourceUpdateBatch *resourceUpdates, |
813 | QRhiCommandBuffer::BeginPassFlags flags) override; |
814 | void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override; |
815 | void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override; |
816 | void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override; |
817 | |
818 | const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override; |
819 | void beginExternal(QRhiCommandBuffer *cb) override; |
820 | void endExternal(QRhiCommandBuffer *cb) override; |
821 | double lastCompletedGpuTime(QRhiCommandBuffer *cb) override; |
822 | |
823 | QList<int> supportedSampleCounts() const override; |
824 | int ubufAlignment() const override; |
825 | bool isYUpInFramebuffer() const override; |
826 | bool isYUpInNDC() const override; |
827 | bool isClipDepthZeroToOne() const override; |
828 | QMatrix4x4 clipSpaceCorrMatrix() const override; |
829 | bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override; |
830 | bool isFeatureSupported(QRhi::Feature feature) const override; |
831 | int resourceLimit(QRhi::ResourceLimit limit) const override; |
832 | const QRhiNativeHandles *nativeHandles() override; |
833 | QRhiDriverInfo driverInfo() const override; |
834 | QRhiStats statistics() override; |
835 | bool makeThreadLocalNativeContextCurrent() override; |
836 | void releaseCachedResources() override; |
837 | bool isDeviceLost() const override; |
838 | |
839 | QByteArray pipelineCacheData() override; |
840 | void setPipelineCacheData(const QByteArray &data) override; |
841 | |
842 | bool ensureContext(QSurface *surface = nullptr) const; |
843 | QSurface *evaluateFallbackSurface() const; |
844 | void executeDeferredReleases(); |
845 | void trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *bufD, QGles2Buffer::Access access); |
846 | void trackedImageBarrier(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Texture::Access access); |
847 | void enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cbD, |
848 | int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc); |
849 | void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); |
850 | void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, |
851 | QGles2Buffer *bufD, |
852 | QRhiPassResourceTracker::BufferAccess access, |
853 | QRhiPassResourceTracker::BufferStage stage); |
854 | void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker, |
855 | QGles2Texture *texD, |
856 | QRhiPassResourceTracker::TextureAccess access, |
857 | QRhiPassResourceTracker::TextureStage stage); |
858 | void executeCommandBuffer(QRhiCommandBuffer *cb); |
859 | void executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2GraphicsPipeline *psD); |
860 | void bindCombinedSampler(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Sampler *samplerD, |
861 | void *ps, uint psGeneration, int glslLocation, |
862 | int *texUnit, bool *activeTexUnitAltered); |
863 | void bindShaderResources(QGles2CommandBuffer *cbD, |
864 | QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs, |
865 | QRhiShaderResourceBindings *srb, |
866 | const uint *dynOfsPairs, int dynOfsCount); |
867 | QGles2RenderTargetData *enqueueBindFramebuffer(QRhiRenderTarget *rt, QGles2CommandBuffer *cbD, |
868 | bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr); |
869 | void enqueueBarriersForPass(QGles2CommandBuffer *cbD); |
870 | int effectiveSampleCount(int sampleCount) const; |
871 | QByteArray shaderSource(const QRhiShaderStage &shaderStage, QShaderVersion *shaderVersion); |
872 | bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, QShaderVersion *shaderVersion); |
873 | bool linkProgram(GLuint program); |
874 | void registerUniformIfActive(const QShaderDescription::BlockVariable &var, |
875 | const QByteArray &namePrefix, int binding, int baseOffset, |
876 | GLuint program, |
877 | QDuplicateTracker<int, 256> *activeUniformLocations, |
878 | QGles2UniformDescriptionVector *dst); |
879 | void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub, |
880 | QDuplicateTracker<int, 256> *activeUniformLocations, QGles2UniformDescriptionVector *dst); |
881 | void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v, |
882 | QGles2SamplerDescriptionVector *dst); |
883 | void gatherGeneratedSamplers(GLuint program, |
884 | const QShader::SeparateToCombinedImageSamplerMapping &mapping, |
885 | QGles2SamplerDescriptionVector *dst); |
886 | void sanityCheckVertexFragmentInterface(const QShaderDescription &vsDesc, const QShaderDescription &fsDesc); |
887 | bool isProgramBinaryDiskCacheEnabled() const; |
888 | |
889 | enum ProgramCacheResult { |
890 | ProgramCacheHit, |
891 | ProgramCacheMiss, |
892 | ProgramCacheError |
893 | }; |
894 | ProgramCacheResult tryLoadFromDiskOrPipelineCache(const QRhiShaderStage *stages, |
895 | int stageCount, |
896 | GLuint program, |
897 | const QVector<QShaderDescription::InOutVariable> &inputVars, |
898 | QByteArray *cacheKey); |
899 | void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey); |
900 | void trySaveToPipelineCache(GLuint program, const QByteArray &cacheKey, bool force = false); |
901 | |
902 | QRhi::Flags rhiFlags; |
903 | QOpenGLContext *ctx = nullptr; |
904 | bool importedContext = false; |
905 | QSurfaceFormat requestedFormat; |
906 | QSurface *fallbackSurface = nullptr; |
907 | QPointer<QWindow> maybeWindow = nullptr; |
908 | QOpenGLContext *maybeShareContext = nullptr; |
909 | mutable bool needsMakeCurrentDueToSwap = false; |
910 | QOpenGLExtensions *f = nullptr; |
911 | void (QOPENGLF_APIENTRYP glPolygonMode) (GLenum, GLenum) = nullptr; |
912 | void(QOPENGLF_APIENTRYP glTexImage1D)(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, |
913 | const void *) = nullptr; |
914 | void(QOPENGLF_APIENTRYP glTexStorage1D)(GLenum, GLint, GLenum, GLsizei) = nullptr; |
915 | void(QOPENGLF_APIENTRYP glTexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum, GLenum, |
916 | const GLvoid *) = nullptr; |
917 | void(QOPENGLF_APIENTRYP glCopyTexSubImage1D)(GLenum, GLint, GLint, GLint, GLint, |
918 | GLsizei) = nullptr; |
919 | void(QOPENGLF_APIENTRYP glCompressedTexImage1D)(GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, |
920 | const GLvoid *) = nullptr; |
921 | void(QOPENGLF_APIENTRYP glCompressedTexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum, |
922 | GLsizei, const GLvoid *) = nullptr; |
923 | void(QOPENGLF_APIENTRYP glFramebufferTexture1D)(GLenum, GLenum, GLenum, GLuint, |
924 | GLint) = nullptr; |
925 | |
926 | uint vao = 0; |
927 | struct Caps { |
928 | Caps() |
929 | : ctxMajor(2), |
930 | ctxMinor(0), |
931 | maxTextureSize(2048), |
932 | maxDrawBuffers(4), |
933 | maxSamples(16), |
934 | maxTextureArraySize(0), |
935 | maxThreadGroupsPerDimension(0), |
936 | maxThreadsPerThreadGroup(0), |
937 | maxThreadGroupsX(0), |
938 | maxThreadGroupsY(0), |
939 | maxThreadGroupsZ(0), |
940 | maxUniformVectors(4096), |
941 | maxVertexInputs(8), |
942 | maxVertexOutputs(8), |
943 | msaaRenderBuffer(false), |
944 | multisampledTexture(false), |
945 | npotTextureFull(true), |
946 | gles(false), |
947 | fixedIndexPrimitiveRestart(false), |
948 | bgraExternalFormat(false), |
949 | bgraInternalFormat(false), |
950 | r8Format(false), |
951 | r16Format(false), |
952 | floatFormats(false), |
953 | rgb10Formats(false), |
954 | depthTexture(false), |
955 | packedDepthStencil(false), |
956 | needsDepthStencilCombinedAttach(false), |
957 | srgbCapableDefaultFramebuffer(false), |
958 | coreProfile(false), |
959 | uniformBuffers(false), |
960 | elementIndexUint(false), |
961 | depth24(false), |
962 | rgba8Format(false), |
963 | instancing(false), |
964 | baseVertex(false), |
965 | compute(false), |
966 | textureCompareMode(false), |
967 | properMapBuffer(false), |
968 | nonBaseLevelFramebufferTexture(false), |
969 | texelFetch(false), |
970 | intAttributes(true), |
971 | screenSpaceDerivatives(false), |
972 | programBinary(false), |
973 | texture3D(false), |
974 | tessellation(false), |
975 | geometryShader(false), |
976 | texture1D(false), |
977 | hasDrawBuffersFunc(false), |
978 | halfAttributes(false) |
979 | { } |
980 | int ctxMajor; |
981 | int ctxMinor; |
982 | int maxTextureSize; |
983 | int maxDrawBuffers; |
984 | int maxSamples; |
985 | int maxTextureArraySize; |
986 | int maxThreadGroupsPerDimension; |
987 | int maxThreadsPerThreadGroup; |
988 | int maxThreadGroupsX; |
989 | int maxThreadGroupsY; |
990 | int maxThreadGroupsZ; |
991 | int maxUniformVectors; |
992 | int maxVertexInputs; |
993 | int maxVertexOutputs; |
994 | // Multisample fb and blit are supported (GLES 3.0 or OpenGL 3.x). Not |
995 | // the same as multisample textures! |
996 | uint msaaRenderBuffer : 1; |
997 | uint multisampledTexture : 1; |
998 | uint npotTextureFull : 1; |
999 | uint gles : 1; |
1000 | uint fixedIndexPrimitiveRestart : 1; |
1001 | uint bgraExternalFormat : 1; |
1002 | uint bgraInternalFormat : 1; |
1003 | uint r8Format : 1; |
1004 | uint r16Format : 1; |
1005 | uint floatFormats : 1; |
1006 | uint rgb10Formats : 1; |
1007 | uint depthTexture : 1; |
1008 | uint packedDepthStencil : 1; |
1009 | uint needsDepthStencilCombinedAttach : 1; |
1010 | uint srgbCapableDefaultFramebuffer : 1; |
1011 | uint coreProfile : 1; |
1012 | uint uniformBuffers : 1; |
1013 | uint elementIndexUint : 1; |
1014 | uint depth24 : 1; |
1015 | uint rgba8Format : 1; |
1016 | uint instancing : 1; |
1017 | uint baseVertex : 1; |
1018 | uint compute : 1; |
1019 | uint textureCompareMode : 1; |
1020 | uint properMapBuffer : 1; |
1021 | uint nonBaseLevelFramebufferTexture : 1; |
1022 | uint texelFetch : 1; |
1023 | uint intAttributes : 1; |
1024 | uint screenSpaceDerivatives : 1; |
1025 | uint programBinary : 1; |
1026 | uint texture3D : 1; |
1027 | uint tessellation : 1; |
1028 | uint geometryShader : 1; |
1029 | uint texture1D : 1; |
1030 | uint hasDrawBuffersFunc : 1; |
1031 | uint halfAttributes : 1; |
1032 | } caps; |
1033 | QGles2SwapChain *currentSwapChain = nullptr; |
1034 | QSet<GLint> supportedCompressedFormats; |
1035 | mutable QList<int> supportedSampleCountList; |
1036 | QRhiGles2NativeHandles nativeHandlesStruct; |
1037 | QRhiDriverInfo driverInfoStruct; |
1038 | mutable bool contextLost = false; |
1039 | |
1040 | struct DeferredReleaseEntry { |
1041 | enum Type { |
1042 | Buffer, |
1043 | Pipeline, |
1044 | Texture, |
1045 | RenderBuffer, |
1046 | TextureRenderTarget |
1047 | }; |
1048 | Type type; |
1049 | union { |
1050 | struct { |
1051 | GLuint buffer; |
1052 | } buffer; |
1053 | struct { |
1054 | GLuint program; |
1055 | } pipeline; |
1056 | struct { |
1057 | GLuint texture; |
1058 | } texture; |
1059 | struct { |
1060 | GLuint renderbuffer; |
1061 | GLuint renderbuffer2; |
1062 | } renderbuffer; |
1063 | struct { |
1064 | GLuint framebuffer; |
1065 | } textureRenderTarget; |
1066 | }; |
1067 | }; |
1068 | QList<DeferredReleaseEntry> releaseQueue; |
1069 | |
1070 | struct OffscreenFrame { |
1071 | OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { } |
1072 | bool active = false; |
1073 | QGles2CommandBuffer cbWrapper; |
1074 | } ofr; |
1075 | |
1076 | QHash<QRhiShaderStage, uint> m_shaderCache; |
1077 | |
1078 | struct PipelineCacheData { |
1079 | quint32 format; |
1080 | QByteArray data; |
1081 | }; |
1082 | QHash<QByteArray, PipelineCacheData> m_pipelineCache; |
1083 | }; |
1084 | |
1085 | Q_DECLARE_TYPEINFO(QRhiGles2::DeferredReleaseEntry, Q_RELOCATABLE_TYPE); |
1086 | |
1087 | QT_END_NAMESPACE |
1088 | |
1089 | #endif |
1090 | |