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