Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qssgrhiparticles.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5#include "qssgrhicontext_p.h"
6
7#include <qfloat16.h>
8
9#include <QtQuick3DUtils/private/qssgutils_p.h>
10
11#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
13#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
14
16
17static const QRhiShaderResourceBinding::StageFlags VISIBILITY_ALL =
19
21{
23 float pointLightConstantAtt[4] = {1.0f, 1.0f, 1.0f, 1.0f};
24 float pointLightLinearAtt[4] = {0.0f};
25 float pointLightQuadAtt[4] = {0.0f};
28 float spotLightConstantAtt[4] = {1.0f, 1.0f, 1.0f, 1.0f};
29 float spotLightLinearAtt[4] = {0.0f};
30 float spotLightQuadAtt[4] = {0.0f};
33 float spotLightConeAngle[4] = {0.0f};
34 float spotLightInnerConeAngle[4] = {0.0f};
35};
36
38 QSSGRhiContext *rhiCtx,
39 char *ubufData,
40 QSSGParticlesRenderable &renderable,
41 const QSSGRenderCameraList &cameras)
42{
43 const QMatrix4x4 clipSpaceCorrMatrix = rhiCtx->rhi()->clipSpaceCorrMatrix();
44
45 QSSGRhiShaderPipeline::CommonUniformIndices &cui = shaders.commonUniformIndices;
46
47 const int viewCount = cameras.count();
48 if (viewCount < 2) {
49 const QMatrix4x4 projection = clipSpaceCorrMatrix * cameras[0]->projection;
50 shaders.setUniform(ubufData, "qt_projectionMatrix", projection.constData(), 16 * sizeof(float), &cui.projectionMatrixIdx);
51 const QMatrix4x4 viewMatrix = cameras[0]->globalTransform.inverted();
52 shaders.setUniform(ubufData, "qt_viewMatrix", viewMatrix.constData(), 16 * sizeof(float), &cui.viewMatrixIdx);
53 } else {
54 QVarLengthArray<QMatrix4x4, 2> projectionMatrices(viewCount);
55 QVarLengthArray<QMatrix4x4, 2> viewMatrices(viewCount);
56 for (int viewIndex = 0; viewIndex < viewCount; ++viewIndex) {
57 projectionMatrices[viewIndex] = clipSpaceCorrMatrix * cameras[viewIndex]->projection;
58 viewMatrices[viewIndex] = cameras[viewIndex]->globalTransform.inverted();
59 }
60 shaders.setUniformArray(ubufData, "qt_projectionMatrix", projectionMatrices.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.projectionMatrixIdx);
61 shaders.setUniformArray(ubufData, "qt_viewMatrix", viewMatrices.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.viewMatrixIdx);
62 }
63
64 const QMatrix4x4 &modelMatrix = renderable.globalTransform;
65 shaders.setUniform(ubufData, "qt_modelMatrix", modelMatrix.constData(), 16 * sizeof(float), &cui.modelMatrixIdx);
66
67 QVector2D oneOverSize = QVector2D(1.0f, 1.0f);
68 auto &particleBuffer = renderable.particles.m_particleBuffer;
69 const quint32 particlesPerSlice = particleBuffer.particlesPerSlice();
70 oneOverSize = QVector2D(1.0f / particleBuffer.size().width(), 1.0f / particleBuffer.size().height());
71 shaders.setUniform(ubufData, "qt_oneOverParticleImageSize", &oneOverSize, 2 * sizeof(float));
72 shaders.setUniform(ubufData, "qt_countPerSlice", &particlesPerSlice, 1 * sizeof(quint32));
73
74 // Global opacity of the particles node
75 shaders.setUniform(ubufData, "qt_opacity", &renderable.opacity, 1 * sizeof(float));
76
77 float blendImages = renderable.particles.m_blendImages ? 1.0f : 0.0f;
78 float imageCount = float(renderable.particles.m_spriteImageCount);
79 float ooImageCount = 1.0f / imageCount;
80
81 QVector4D spriteConfig(imageCount, ooImageCount, 0.0f, blendImages);
82 shaders.setUniform(ubufData, "qt_spriteConfig", &spriteConfig, 4 * sizeof(float));
83
84 const float billboard = renderable.particles.m_billboard ? 1.0f : 0.0f;
85 shaders.setUniform(ubufData, "qt_billboard", &billboard, 1 * sizeof(float));
86
87 // Lights
88 QVector3D theLightAmbientTotal;
89 bool hasLights = !renderable.particles.m_lights.isEmpty();
90 int pointLight = 0;
91 int spotLight = 0;
92 if (hasLights) {
93 ParticleLightData lightData;
94 auto &lights = renderable.lights;
95 for (quint32 lightIdx = 0, lightEnd = lights.size();
96 lightIdx < lightEnd && lightIdx < QSSG_MAX_NUM_LIGHTS; ++lightIdx) {
97 QSSGRenderLight *theLight(lights[lightIdx].light);
98 // Ignore lights which are not specified for the particle
99 if (!renderable.particles.m_lights.contains(theLight))
100 continue;
101 if (theLight->type == QSSGRenderLight::Type::DirectionalLight) {
102 theLightAmbientTotal += theLight->m_diffuseColor * theLight->m_brightness;
103 } else if (theLight->type == QSSGRenderLight::Type::PointLight && pointLight < 4) {
104 lightData.pointLightColor[pointLight] = QVector4D(theLight->m_diffuseColor * theLight->m_brightness, 1.0f);
105 lightData.pointLightPos[pointLight] = QVector4D(theLight->getGlobalPos(), 1.0f);
106 lightData.pointLightConstantAtt[pointLight] = QSSGUtils::aux::translateConstantAttenuation(theLight->m_constantFade);
107 lightData.pointLightLinearAtt[pointLight] = QSSGUtils::aux::translateLinearAttenuation(theLight->m_linearFade);
108 lightData.pointLightQuadAtt[pointLight] = QSSGUtils::aux::translateQuadraticAttenuation(theLight->m_quadraticFade);
109 pointLight++;
110 } else if (theLight->type == QSSGRenderLight::Type::SpotLight && spotLight < 4) {
111 lightData.spotLightColor[spotLight] = QVector4D(theLight->m_diffuseColor * theLight->m_brightness, 1.0f);
112 lightData.spotLightPos[spotLight] = QVector4D(theLight->getGlobalPos(), 1.0f);
113 lightData.spotLightDir[spotLight] = QVector4D(lights[lightIdx].direction, 0.0f);
114 lightData.spotLightConstantAtt[spotLight] = QSSGUtils::aux::translateConstantAttenuation(theLight->m_constantFade);
115 lightData.spotLightLinearAtt[spotLight] = QSSGUtils::aux::translateLinearAttenuation(theLight->m_linearFade);
116 lightData.spotLightQuadAtt[spotLight] = QSSGUtils::aux::translateQuadraticAttenuation(theLight->m_quadraticFade);
117 float coneAngle = theLight->m_coneAngle;
118 // Inner cone angle must always be < cone angle, to not have possible undefined behavior for shader smoothstep
119 float innerConeAngle = std::min(theLight->m_innerConeAngle, coneAngle - 0.01f);
120 lightData.spotLightConeAngle[spotLight] = qDegreesToRadians(coneAngle);
121 lightData.spotLightInnerConeAngle[spotLight] = qDegreesToRadians(innerConeAngle);
122 spotLight++;
123 }
124 theLightAmbientTotal += theLight->m_ambientColor;
125 }
126 // Copy light data
127 int lightOffset = shaders.offsetOfUniform("qt_pointLightPosition");
128 if (lightOffset >= 0)
129 memcpy(ubufData + lightOffset, &lightData, sizeof(ParticleLightData));
130 }
131 shaders.setUniform(ubufData, "qt_light_ambient_total", &theLightAmbientTotal, 3 * sizeof(float), &cui.light_ambient_totalIdx);
132 int enablePointLights = pointLight > 0 ? 1 : 0;
133 int enableSpotLights = spotLight > 0 ? 1 : 0;
134 shaders.setUniform(ubufData, "qt_pointLights", &enablePointLights, sizeof(int));
135 shaders.setUniform(ubufData, "qt_spotLights", &enableSpotLights, sizeof(int));
136
137 // Line particle uniform
138 int segmentCount = particleBuffer.segments();
139 if (segmentCount) {
140 shaders.setUniform(ubufData, "qt_lineSegmentCount", &segmentCount, sizeof(int));
141 float alphaFade = renderable.particles.m_alphaFade;
142 float sizeModifier = renderable.particles.m_sizeModifier;
143 float texcoordScale = renderable.particles.m_texcoordScale;
144 auto image = renderable.firstImage;
145 if (image && image->m_texture.m_texture) {
146 const auto size = image->m_texture.m_texture->pixelSize();
147 texcoordScale *= float(size.height()) / float(size.width());
148 }
149 shaders.setUniform(ubufData, "qt_alphaFade", &alphaFade, sizeof(float));
150 shaders.setUniform(ubufData, "qt_sizeModifier", &sizeModifier, sizeof(float));
151 shaders.setUniform(ubufData, "qt_texcoordScale", &texcoordScale, sizeof(float));
152 }
153}
154
156 char *ubufData,
157 const QSSGRenderModel *model,
159{
160 auto &particleBuffer = *model->particleBuffer;
161 const quint32 particlesPerSlice = particleBuffer.particlesPerSlice();
162 const QVector2D oneOverSize = QVector2D(1.0f / particleBuffer.size().width(), 1.0f / particleBuffer.size().height());
163 shaderPipeline.setUniform(ubufData, "qt_oneOverParticleImageSize", &oneOverSize, 2 * sizeof(float));
164 shaderPipeline.setUniform(ubufData, "qt_countPerSlice", &particlesPerSlice, sizeof(quint32));
165 const QMatrix4x4 &particleMatrix = model->particleMatrix;
166 shaderPipeline.setUniform(ubufData, "qt_particleMatrix", &particleMatrix, 16 * sizeof(float));
167 shaderPipeline.setUniform(ubufData, "qt_particleIndexOffset", &offset, sizeof(quint32));
168}
169
171{
172 switch (mode) {
178 break;
184 break;
185 default:
186 // Source over as default
191 break;
192
193 }
194}
195
196static void sortParticles(QByteArray &result, QList<QSSGRhiSortData> &sortData,
197 const QSSGParticleBuffer &buffer, const QSSGRenderParticles &particles,
198 const QVector3D &cameraDirection, bool animatedParticles)
199{
200 const QMatrix4x4 &invModelMatrix = particles.globalTransform.inverted();
201 QVector3D dir = invModelMatrix.map(cameraDirection);
203 const auto segments = buffer.segments();
204 auto particleCount = buffer.particleCount();
205 const bool lineParticles = segments > 0;
206 if (lineParticles)
207 particleCount /= segments;
208 sortData.resize(particleCount);
209 sortData.fill({});
210
211 const auto srcParticlePointer = [](int line, int segment, int sc, int ss, int pps, const char *source) -> const QSSGLineParticle * {
212 int pi = (line * sc + segment) / pps;
213 int i = (line * sc + segment) % pps;
214 const QSSGLineParticle *sp = reinterpret_cast<const QSSGLineParticle *>(source + pi * ss);
215 return sp + i;
216 };
217
218 // create sort data
219 {
220 const auto slices = buffer.sliceCount();
221 const auto ss = buffer.sliceStride();
222 const auto pps = buffer.particlesPerSlice();
223
224 QSSGRhiSortData *dst = sortData.data();
225 const char *source = buffer.pointer();
226 const char *begin = source;
227 int i = 0;
228 if (lineParticles) {
229 for (i = 0; i < particleCount; i++) {
230 QSSGRhiSortData lineData;
231 const QSSGLineParticle *lineBegin = srcParticlePointer(i, 0, segments, ss, pps, source);
232 lineData.indexOrOffset = i;
233 lineData.d = QVector3D::dotProduct(lineBegin->position, n);
234 for (int j = 1; j < buffer.segments(); j++) {
235 const QSSGLineParticle *p = srcParticlePointer(i, j, segments, ss, pps, source);
236 lineData.d = qMin(lineData.d, QVector3D::dotProduct(p->position, n));
237 }
238 *dst++ = lineData;
239 }
240 } else if (animatedParticles) {
241 for (int s = 0; s < slices; s++) {
242 const QSSGParticleAnimated *sp = reinterpret_cast<const QSSGParticleAnimated *>(source);
243 for (int p = 0; p < pps && i < particleCount; p++) {
244 *dst = { QVector3D::dotProduct(sp->position, n), int(reinterpret_cast<const char *>(sp) - begin)};
245 sp++;
246 dst++;
247 i++;
248 }
249 source += ss;
250 }
251 } else {
252 for (int s = 0; s < slices; s++) {
253 const QSSGParticleSimple *sp = reinterpret_cast<const QSSGParticleSimple *>(source);
254 for (int p = 0; p < pps && i < particleCount; p++) {
255 *dst = { QVector3D::dotProduct(sp->position, n), int(reinterpret_cast<const char *>(sp) - begin)};
256 sp++;
257 dst++;
258 i++;
259 }
260 source += ss;
261 }
262 }
263 }
264
265 // sort
266 result.resize(buffer.bufferSize());
267 std::sort(sortData.begin(), sortData.end(), [](const QSSGRhiSortData &a, const QSSGRhiSortData &b){
268 return a.d > b.d;
269 });
270
271 auto copyParticles = [&](QByteArray &dst, const QList<QSSGRhiSortData> &data, const QSSGParticleBuffer &buffer) {
272 const auto slices = buffer.sliceCount();
273 const auto ss = buffer.sliceStride();
274 const auto pps = buffer.particlesPerSlice();
275 const QSSGRhiSortData *sdata = data.data();
276 char *dest = dst.data();
277 const char *source = buffer.pointer();
278 int i = 0;
279 if (lineParticles) {
280 int seg = 0;
281 for (int s = 0; s < slices; s++) {
282 QSSGLineParticle *dp = reinterpret_cast<QSSGLineParticle *>(dest);
283 for (int p = 0; p < pps && i < particleCount; p++) {
284 *dp = *srcParticlePointer(sdata->indexOrOffset, seg, segments, ss, pps, source);
285 dp++;
286 seg++;
287 if (seg == segments) {
288 sdata++;
289 i++;
290 seg = 0;
291 }
292 }
293 dest += ss;
294 }
295 } else if (animatedParticles) {
296 for (int s = 0; s < slices; s++) {
297 QSSGParticleAnimated *dp = reinterpret_cast<QSSGParticleAnimated *>(dest);
298 for (int p = 0; p < pps && i < particleCount; p++) {
299 *dp = *reinterpret_cast<const QSSGParticleAnimated *>(source + sdata->indexOrOffset);
300 dp++;
301 sdata++;
302 i++;
303 }
304 dest += ss;
305 }
306 } else {
307 for (int s = 0; s < slices; s++) {
308 QSSGParticleSimple *dp = reinterpret_cast<QSSGParticleSimple *>(dest);
309 for (int p = 0; p < pps && i < particleCount; p++) {
310 *dp = *reinterpret_cast<const QSSGParticleSimple *>(source + sdata->indexOrOffset);
311 dp++;
312 sdata++;
313 i++;
314 }
315 dest += ss;
316 }
317 }
318 };
319
320 // write result
321 copyParticles(result, sortData, buffer);
322}
323
325{
326 if (!convert)
327 return data;
328 int count = data.size() / 4;
329 if (dest.size() != count * 2)
330 dest.resize(2 * count);
331 qFloatToFloat16(reinterpret_cast<qfloat16 *>(dest.data()), reinterpret_cast<const float *>(data.constData()), count);
332 return dest;
333}
334
336 QSSGPassKey passKey,
337 QSSGRhiContext *rhiCtx,
339 QSSGParticlesRenderable &renderable,
340 const QSSGLayerRenderData &inData,
341 QRhiRenderPassDescriptor *renderPassDescriptor,
342 int samples,
343 int viewCount,
344 QSSGRenderCamera *alteredCamera,
347{
348 const void *node = &renderable.particles;
349 const bool needsConversion = !rhiCtx->rhi()->isTextureFormatSupported(QRhiTexture::RGBA32F);
350
351 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
352 QSSGRhiDrawCallData &dcd = QSSGRhiContextPrivate::get(rhiCtx)->drawCallData({ passKey, node, entry, cubeFaceIdx });
353 shaderPipeline.ensureUniformBuffer(&dcd.ubuf);
354
355 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
356 if (!alteredCamera) {
357 updateUniformsForParticles(shaderPipeline, rhiCtx, ubufData, renderable, inData.renderedCameras);
358 } else {
359 QSSGRenderCameraList cameras({ alteredCamera });
360 updateUniformsForParticles(shaderPipeline, rhiCtx, ubufData, renderable, cameras);
361 }
362 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
363
364 QSSGRhiParticleData &particleData = QSSGRhiContextPrivate::get(rhiCtx)->particleData(&renderable.particles);
365 const QSSGParticleBuffer &particleBuffer = renderable.particles.m_particleBuffer;
366 int particleCount = particleBuffer.particleCount();
367 if (particleData.texture == nullptr || particleData.particleCount != particleCount) {
368 QSize size(particleBuffer.size());
369 if (!particleData.texture) {
370 particleData.texture = rhiCtx->rhi()->newTexture(needsConversion ? QRhiTexture::RGBA16F : QRhiTexture::RGBA32F, size);
371 particleData.texture->create();
372 } else {
373 particleData.texture->setPixelSize(size);
374 particleData.texture->create();
375 }
376 particleData.particleCount = particleCount;
377 }
378
379 bool sortingChanged = particleData.sorting != renderable.particles.m_depthSorting;
380 if (sortingChanged && !renderable.particles.m_depthSorting) {
381 particleData.sortData.clear();
382 particleData.sortedData.clear();
383 }
384 particleData.sorting = renderable.particles.m_depthSorting;
385
386 QByteArray uploadData;
387
388 if (renderable.particles.m_depthSorting) {
389 bool animatedParticles = renderable.particles.m_featureLevel == QSSGRenderParticles::FeatureLevel::Animated;
390 if (!alteredCamera)
391 sortParticles(particleData.sortedData, particleData.sortData, particleBuffer, renderable.particles, inData.renderedCameraData.value()[0].direction, animatedParticles);
392 else
393 sortParticles(particleData.sortedData, particleData.sortData, particleBuffer, renderable.particles, alteredCamera->getScalingCorrectDirection(), animatedParticles);
394 uploadData = convertParticleData(particleData.convertData, particleData.sortedData, needsConversion);
395 } else {
396 uploadData = convertParticleData(particleData.convertData, particleBuffer.data(), needsConversion);
397 }
398
401 upload.setData(uploadData);
403 rub->uploadTexture(particleData.texture, uploadDesc);
404 rhiCtx->commandBuffer()->resourceUpdate(rub);
405
408 ia.inputLayout = QRhiVertexInputLayout();
409 ia.inputs.clear();
410
411 ps->samples = samples;
412 ps->viewCount = viewCount;
414 if (renderable.renderableFlags.hasTransparency())
415 fillTargetBlend(ps->targetBlend, renderable.particles.m_blendMode);
416 else
418
420 bindings.addUniformBuffer(0, VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline.ub0Size());
421
422 // Texture maps
423 // we only have one image
424 QSSGRenderableImage *renderableImage = renderable.firstImage;
425
426 int samplerBinding = shaderPipeline.bindingForTexture("qt_sprite");
427 if (samplerBinding >= 0) {
428 QRhiTexture *texture = renderableImage ? renderableImage->m_texture.m_texture : nullptr;
429 if (samplerBinding >= 0 && texture) {
430 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
431 QRhiSampler *sampler = rhiCtx->sampler({ QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
432 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
433 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
434 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
435 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
436 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
437 });
439 } else {
441 QRhiTexture *texture = rhiCtx->dummyTexture({}, rub, QSize(4, 4), Qt::white);
442 rhiCtx->commandBuffer()->resourceUpdate(rub);
449 });
451 }
452 }
453
454 samplerBinding = shaderPipeline.bindingForTexture("qt_particleTexture");
455 if (samplerBinding >= 0) {
456 QRhiTexture *texture = particleData.texture;
457 if (samplerBinding >= 0 && texture) {
464 });
466 }
467 }
468
469 samplerBinding = shaderPipeline.bindingForTexture("qt_colorTable");
470 if (samplerBinding >= 0) {
471 bool hasTexture = false;
472 if (renderable.colorTable) {
473 QRhiTexture *texture = renderable.colorTable->m_texture.m_texture;
474 if (texture) {
475 hasTexture = true;
482 });
484 }
485 }
486
487 if (!hasTexture) {
489 QRhiTexture *texture = rhiCtx->dummyTexture({}, rub, QSize(4, 4), Qt::white);
490 rhiCtx->commandBuffer()->resourceUpdate(rub);
497 });
499 }
500 }
501
503
504 // TODO: This is identical to other renderables. Make into a function?
505 QRhiShaderResourceBindings *&srb = dcd.srb;
506 bool srbChanged = false;
507 if (!srb || bindings != dcd.bindings) {
508 srb = rhiCtxD->srb(bindings);
509 dcd.bindings = bindings;
510 srbChanged = true;
511 }
512
513 if (cubeFace == QSSGRenderTextureCubeFaceNone)
514 renderable.rhiRenderData.mainPass.srb = srb;
515 else
516 renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
517
518 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
519 if (dcd.pipeline
520 && !srbChanged
521 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
522 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
523 && dcd.ps == *ps)
524 {
525 if (cubeFace == QSSGRenderTextureCubeFaceNone)
526 renderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
527 else
528 renderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
529 } else {
530 if (cubeFace == QSSGRenderTextureCubeFaceNone) {
531 renderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
532 renderPassDescriptor,
533 srb);
534 dcd.pipeline = renderable.rhiRenderData.mainPass.pipeline;
535 } else {
536 renderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
537 renderPassDescriptor,
538 srb);
539 dcd.pipeline = renderable.rhiRenderData.reflectionPass.pipeline;
540 }
541 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
542 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
543 dcd.ps = *ps;
544 }
545}
546
548 QSSGRhiContext *rhiCtx,
550 const QSSGRenderModel *model)
551{
553 QSSGRhiParticleData &particleData = rhiCtxD->particleData(model);
554 const QSSGParticleBuffer &particleBuffer = *model->particleBuffer;
555 int particleCount = particleBuffer.particleCount();
556 bool update = particleBuffer.serial() != particleData.serial;
557 const bool needsConversion = !rhiCtx->rhi()->isTextureFormatSupported(QRhiTexture::RGBA32F);
558 if (particleData.texture == nullptr || particleData.particleCount != particleCount) {
559 QSize size(particleBuffer.size());
560 if (!particleData.texture) {
561 particleData.texture = rhiCtx->rhi()->newTexture(needsConversion ? QRhiTexture::RGBA16F : QRhiTexture::RGBA32F, size);
562 particleData.texture->create();
563 } else {
564 particleData.texture->setPixelSize(size);
565 particleData.texture->create();
566 }
567 particleData.particleCount = particleCount;
568 update = true;
569 }
570
571 if (update) {
574 upload.setData(convertParticleData(particleData.convertData, particleBuffer.data(), needsConversion));
576 rub->uploadTexture(particleData.texture, uploadDesc);
577 rhiCtx->commandBuffer()->resourceUpdate(rub);
578 }
579 particleData.serial = particleBuffer.serial();
580 int samplerBinding = shaderPipeline.bindingForTexture("qt_particleTexture");
581 if (samplerBinding >= 0) {
582 QRhiTexture *texture = particleData.texture;
583 if (samplerBinding >= 0 && texture) {
590 });
592 }
593 }
594}
595
597 QSSGParticlesRenderable &renderable,
598 bool *needsSetViewport,
601{
602 QRhiGraphicsPipeline *ps = renderable.rhiRenderData.mainPass.pipeline;
603 QRhiShaderResourceBindings *srb = renderable.rhiRenderData.mainPass.srb;
604
605 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
606 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
607 ps = renderable.rhiRenderData.reflectionPass.pipeline;
608 srb = renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx];
609 }
610
611 if (!ps || !srb)
612 return;
613
614 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
615
617 // QRhi optimizes out unnecessary binding of the same pipline
618 cb->setGraphicsPipeline(ps);
619 cb->setVertexInput(0, 0, nullptr);
620 cb->setShaderResources(srb);
621
622 if (needsSetViewport && *needsSetViewport) {
623 cb->setViewport(state.viewport);
624 *needsSetViewport = false;
625 }
626 if (renderable.particles.m_featureLevel >= QSSGRenderParticles::FeatureLevel::Line) {
627 // draw triangle strip with 2 * segmentCount vertices N times
628 int S = renderable.particles.m_particleBuffer.segments();
629 int N = renderable.particles.m_particleBuffer.particleCount() / S;
630 cb->draw(2 * S, N);
631 QSSGRHICTX_STAT(rhiCtx, draw(2 * S, N));
632 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderCall, (2 * S | quint64(N) << 32), renderable.particles.profilingId);
633 } else {
634 // draw triangle strip with 2 triangles N times
635 cb->draw(4, renderable.particles.m_particleBuffer.particleCount());
636 QSSGRHICTX_STAT(rhiCtx, draw(4, renderable.particles.m_particleBuffer.particleCount()));
637 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderCall, (4 | quint64(renderable.particles.m_particleBuffer.particleCount()) << 32), renderable.particles.profilingId);
638 }
639}
640
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
void clear()
Clears the contents of the byte array and makes it null.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
void clear()
Definition qlist.h:434
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
QMatrix4x4 inverted(bool *invertible=nullptr) const
Returns the inverse of this matrix.
const float * constData() const
Returns a constant pointer to the raw data of this matrix.
Definition qmatrix4x4.h:147
\inmodule QtGui
Definition qrhi.h:1651
void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates)
Sometimes committing resource updates is necessary or just more convenient without starting a render ...
Definition qrhi.cpp:9384
\inmodule QtGui
Definition qrhi.h:1270
\inmodule QtGui
Definition qrhi.h:1142
\inmodule QtGui
Definition qrhi.h:1731
\inmodule QtGui
Definition qrhi.h:1030
@ ClampToEdge
Definition qrhi.h:1040
\inmodule QtGui
Definition qrhi.h:1214
void setData(const QByteArray &data)
Sets data.
Definition qrhi.h:667
\inmodule QtGui
Definition qrhi.h:716
\inmodule QtGui
Definition qrhi.h:693
\inmodule QtGui
Definition qrhi.h:895
@ MipMapped
Definition qrhi.h:900
virtual bool create()=0
Creates the corresponding native graphics resources.
@ RGBA32F
Definition qrhi.h:926
@ RGBA16F
Definition qrhi.h:925
Flags flags() const
Definition qrhi.h:992
void setPixelSize(const QSize &sz)
Sets the texture size, specified in pixels, to sz.
Definition qrhi.h:976
\inmodule QtGui
Definition qrhi.h:321
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags={}) const
Definition qrhi.cpp:10102
QMatrix4x4 clipSpaceCorrMatrix() const
Definition qrhi.cpp:10091
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10562
QRhiResourceUpdateBatch * nextResourceUpdateBatch()
Definition qrhi.cpp:9252
static constexpr QSSGRenderTextureCubeFaceT indexOfCubeFace(QSSGRenderTextureCubeFace face) noexcept
static QSSGGraphicsPipelineStateKey create(const QSSGRhiGraphicsPipelineState &state, const QRhiRenderPassDescriptor *rpDesc, const QRhiShaderResourceBindings *srb)
static void updateUniformsForParticleModel(QSSGRhiShaderPipeline &shaderPipeline, char *ubufData, const QSSGRenderModel *model, quint32 offset)
static void rhiPrepareRenderable(QSSGRhiShaderPipeline &shaderPipeline, QSSGPassKey passKey, QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QSSGParticlesRenderable &renderable, const QSSGLayerRenderData &inData, QRhiRenderPassDescriptor *renderPassDescriptor, int samples, int viewCount, QSSGRenderCamera *alteredCamera=nullptr, QSSGRenderTextureCubeFace cubeFace=QSSGRenderTextureCubeFaceNone, QSSGReflectionMapEntry *entry=nullptr)
static void updateUniformsForParticles(QSSGRhiShaderPipeline &shaderPipeline, QSSGRhiContext *rhiCtx, char *ubufData, QSSGParticlesRenderable &renderable, const QSSGRenderCameraList &cameras)
static void rhiRenderRenderable(QSSGRhiContext *rhiCtx, QSSGParticlesRenderable &renderable, bool *needsSetViewport, QSSGRenderTextureCubeFace cubeFace, const QSSGRhiGraphicsPipelineState &state)
static void prepareParticlesForModel(QSSGRhiShaderPipeline &shaderPipeline, QSSGRhiContext *rhiCtx, QSSGRhiShaderResourceBindingList &bindings, const QSSGRenderModel *model)
static QSSGRhiContextPrivate * get(QSSGRhiContext *q)
\inmodule QtQuick3D
QRhiCommandBuffer * commandBuffer() const
QRhiTexture * dummyTexture(QRhiTexture::Flags flags, QRhiResourceUpdateBatch *rub, const QSize &size=QSize(64, 64), const QColor &fillColor=Qt::black, int arraySize=0)
QRhi * rhi() const
QRhiSampler * sampler(const QSSGRhiSamplerDescription &samplerDescription)
QRhiGraphicsPipeline::CullMode cullMode
QRhiGraphicsPipeline::TargetBlend targetBlend
void ensureUniformBuffer(QRhiBuffer **ubuf)
int bindingForTexture(const char *name, int hint=-1)
void setUniform(char *ubufData, const char *name, const void *data, size_t size, int *storeIndex=nullptr, UniformFlags flags={})
void addUniformBuffer(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiBuffer *buf, int offset=0, int size=0)
void addTexture(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
\inmodule QtCore
Definition qsize.h:25
QString normalized(NormalizationForm mode, QChar::UnicodeVersion version=QChar::Unicode_Unassigned) const
Returns the string in the given Unicode normalization mode, according to the given version of the Uni...
Definition qstring.cpp:8475
qsizetype count() const
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
static constexpr float dotProduct(QVector3D v1, QVector3D v2) noexcept
Returns the dot product of v1 and v2.
Definition qvectornd.h:770
The QVector4D class represents a vector or vertex in 4D space.
Definition qvectornd.h:330
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:47
direction
else opt state
[0]
QRhiSampler::Filter toRhi(QSSGRenderTextureFilterOp op)
Q_DECL_CONSTEXPR float translateLinearAttenuation(float attenuation)
Definition qssgutils_p.h:44
Q_DECL_CONSTEXPR float translateConstantAttenuation(float attenuation)
Definition qssgutils_p.h:42
Q_DECL_CONSTEXPR float translateQuadraticAttenuation(float attenuation)
Definition qssgutils_p.h:46
Combined button and popup list for selecting options.
@ white
Definition qnamespace.h:31
Definition image.cpp:4
Q_CORE_EXPORT void qFloatToFloat16(qfloat16 *, const float *, qsizetype length) noexcept
constexpr float qDegreesToRadians(float degrees)
Definition qmath.h:260
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLboolean GLboolean GLboolean b
GLsizei samples
GLenum mode
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint sampler
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLenum GLenum dst
GLenum GLuint texture
GLenum GLuint GLintptr offset
GLfloat n
GLsizei GLsizei GLchar * source
GLdouble s
[6]
Definition qopenglext.h:235
GLuint segment
GLuint entry
GLuint segments
GLsizei GLsizei GLuint * shaders
Definition qopenglext.h:677
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
static constexpr To convert(const std::array< Mapping, N > &mapping, From Mapping::*from, To Mapping::*to, From value, To defaultValue)
#define Q_QUICK3D_PROFILE_START(Type)
#define Q_QUICK3D_PROFILE_END_WITH_ID(Type, Payload, POID)
static int segmentCount(const QPainterPath &path, qreal pathLength)
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
QSSGRenderTextureCubeFace
constexpr QSSGRenderTextureCubeFace QSSGRenderTextureCubeFaceNone
#define QSSGRHICTX_STAT(ctx, f)
#define QSSG_MAX_NUM_LIGHTS
static QByteArray convertParticleData(QByteArray &dest, const QByteArray &data, bool convert)
static void fillTargetBlend(QRhiGraphicsPipeline::TargetBlend &targetBlend, QSSGRenderParticles::BlendMode mode)
static QT_BEGIN_NAMESPACE const QRhiShaderResourceBinding::StageFlags VISIBILITY_ALL
static void sortParticles(QByteArray &result, QList< QSSGRhiSortData > &sortData, const QSSGParticleBuffer &buffer, const QSSGRenderParticles &particles, const QVector3D &cameraDirection, bool animatedParticles)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define sp
unsigned int quint32
Definition qtypes.h:50
unsigned long long quint64
Definition qtypes.h:61
QSqlQueryModel * model
[16]
QString dir
[11]
myFilter draw(painter, QPoint(0, 0), originalPixmap)
QVector4D spotLightDir[4]
QVector4D pointLightColor[4]
QVector4D spotLightPos[4]
QVector4D spotLightColor[4]
QVector4D pointLightPos[4]
QByteArray data() const
QMatrix4x4 globalTransform
static const InputAssemblerState & get(const QSSGRhiGraphicsPipelineState &ps)
QList< QSSGRhiSortData > sortData