38 QSSGRhiShaderPipeline &shaders,
39 QSSGRhiContext *rhiCtx,
41 QSSGParticlesRenderable &renderable,
42 const QSSGRenderCameraList &cameras)
44 const QMatrix4x4 clipSpaceCorrMatrix = rhiCtx->rhi()->clipSpaceCorrMatrix();
46 QSSGRhiShaderPipeline::CommonUniformIndices &cui = shaders.commonUniformIndices;
48 const int viewCount = cameras.count();
51 QMatrix4x4 camGlobalTransforms[2] { QMatrix4x4{Qt::Uninitialized}, QMatrix4x4{Qt::Uninitialized} };
53 camGlobalTransforms[0] = inData.getGlobalTransform(*cameras[0]);
55 for (size_t viewIndex = 0; viewIndex != std::size(camGlobalTransforms); ++viewIndex)
56 camGlobalTransforms[viewIndex] = inData.getGlobalTransform(*cameras[viewIndex]);
60 const QMatrix4x4 projection = clipSpaceCorrMatrix * cameras[0]->projection;
61 shaders.setUniform(ubufData,
"qt_projectionMatrix", projection.constData(), 16 *
sizeof(
float), &cui.projectionMatrixIdx);
62 const QMatrix4x4 viewMatrix = camGlobalTransforms[0].inverted();
63 shaders.setUniform(ubufData,
"qt_viewMatrix", viewMatrix.constData(), 16 *
sizeof(
float), &cui.viewMatrixIdx);
65 QVarLengthArray<QMatrix4x4, 2> projectionMatrices(viewCount);
66 QVarLengthArray<QMatrix4x4, 2> viewMatrices(viewCount);
67 for (
int viewIndex = 0; viewIndex < viewCount; ++viewIndex) {
68 projectionMatrices[viewIndex] = clipSpaceCorrMatrix * cameras[viewIndex]->projection;
69 viewMatrices[viewIndex] = camGlobalTransforms[viewIndex].inverted();
71 shaders.setUniformArray(ubufData,
"qt_projectionMatrix", projectionMatrices.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.projectionMatrixIdx);
72 shaders.setUniformArray(ubufData,
"qt_viewMatrix", viewMatrices.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.viewMatrixIdx);
75 const QMatrix4x4 &modelMatrix = renderable.globalTransform;
76 shaders.setUniform(ubufData,
"qt_modelMatrix", modelMatrix.constData(), 16 *
sizeof(
float), &cui.modelMatrixIdx);
78 const QVector2D camProperties(cameras[0]->clipPlanes);
79 shaders.setUniform(ubufData,
"qt_cameraProperties", &camProperties, 2 *
sizeof(
float), &cui.cameraPropertiesIdx);
81 QVector2D oneOverSize = QVector2D(1.0f, 1.0f);
82 auto &particleBuffer = renderable.particles.m_particleBuffer;
83 const quint32 particlesPerSlice = particleBuffer.particlesPerSlice();
84 oneOverSize = QVector2D(1.0f / particleBuffer.size().width(), 1.0f / particleBuffer.size().height());
85 shaders.setUniform(ubufData,
"qt_oneOverParticleImageSize", &oneOverSize, 2 *
sizeof(
float));
86 shaders.setUniform(ubufData,
"qt_countPerSlice", &particlesPerSlice, 1 *
sizeof(quint32));
89 shaders.setUniform(ubufData,
"qt_opacity", &renderable.opacity, 1 *
sizeof(
float));
91 float blendImages = renderable.particles.m_blendImages ? 1.0f : 0.0f;
92 float imageCount =
float(renderable.particles.m_spriteImageCount);
93 float ooImageCount = 1.0f / imageCount;
95 QVector4D spriteConfig(imageCount, ooImageCount, 0.0f, blendImages);
96 shaders.setUniform(ubufData,
"qt_spriteConfig", &spriteConfig, 4 *
sizeof(
float));
98 const float billboard = renderable.particles.m_billboard ? 1.0f : 0.0f;
99 shaders.setUniform(ubufData,
"qt_billboard", &billboard, 1 *
sizeof(
float));
102 QVector3D theLightAmbientTotal;
103 bool hasLights = !renderable.particles.m_lights.isEmpty();
108 auto &lights = renderable.lights;
109 for (quint32 lightIdx = 0, lightEnd = lights.size();
111 QSSGRenderLight *theLight(lights[lightIdx].light);
113 if (!renderable.particles.m_lights.contains(theLight))
116 const QMatrix4x4 lightGlobalTransform = inData.getGlobalTransform(*theLight);
118 if (theLight->type == QSSGRenderLight::Type::DirectionalLight) {
119 theLightAmbientTotal += theLight->m_diffuseColor * theLight->m_brightness;
120 }
else if (theLight->type == QSSGRenderLight::Type::PointLight && pointLight < 4) {
121 lightData.pointLightColor[pointLight] = QVector4D(theLight->m_diffuseColor * theLight->m_brightness, 1.0f);
122 lightData.pointLightPos[pointLight] = QVector4D(QSSGRenderNode::getGlobalPos(lightGlobalTransform), 1.0f);
123 lightData.pointLightConstantAtt[pointLight] = QSSGUtils::aux::translateConstantAttenuation(theLight->m_constantFade);
124 lightData.pointLightLinearAtt[pointLight] = QSSGUtils::aux::translateLinearAttenuation(theLight->m_linearFade);
125 lightData.pointLightQuadAtt[pointLight] = QSSGUtils::aux::translateQuadraticAttenuation(theLight->m_quadraticFade);
127 }
else if (theLight->type == QSSGRenderLight::Type::SpotLight && spotLight < 4) {
128 lightData.spotLightColor[spotLight] = QVector4D(theLight->m_diffuseColor * theLight->m_brightness, 1.0f);
129 lightData.spotLightPos[spotLight] = QVector4D(QSSGRenderNode::getGlobalPos(lightGlobalTransform), 1.0f);
130 lightData.spotLightDir[spotLight] = QVector4D(lights[lightIdx].direction, 0.0f);
131 lightData.spotLightConstantAtt[spotLight] = QSSGUtils::aux::translateConstantAttenuation(theLight->m_constantFade);
132 lightData.spotLightLinearAtt[spotLight] = QSSGUtils::aux::translateLinearAttenuation(theLight->m_linearFade);
133 lightData.spotLightQuadAtt[spotLight] = QSSGUtils::aux::translateQuadraticAttenuation(theLight->m_quadraticFade);
134 float coneAngle = theLight->m_coneAngle;
136 float innerConeAngle = std::min(theLight->m_innerConeAngle, coneAngle - 0.01f);
137 lightData.spotLightConeAngle[spotLight] = qDegreesToRadians(coneAngle);
138 lightData.spotLightInnerConeAngle[spotLight] = qDegreesToRadians(innerConeAngle);
141 theLightAmbientTotal += theLight->m_ambientColor;
144 int lightOffset = shaders.offsetOfUniform(
"qt_pointLightPosition");
145 if (lightOffset >= 0)
146 memcpy(ubufData + lightOffset, &lightData,
sizeof(ParticleLightData));
148 shaders.setUniform(ubufData,
"qt_light_ambient_total", &theLightAmbientTotal, 3 *
sizeof(
float), &cui.light_ambient_totalIdx);
149 int enablePointLights = pointLight > 0 ? 1 : 0;
150 int enableSpotLights = spotLight > 0 ? 1 : 0;
151 shaders.setUniform(ubufData,
"qt_pointLights", &enablePointLights,
sizeof(
int));
152 shaders.setUniform(ubufData,
"qt_spotLights", &enableSpotLights,
sizeof(
int));
155 int segmentCount = particleBuffer.segments();
157 shaders.setUniform(ubufData,
"qt_lineSegmentCount", &segmentCount,
sizeof(
int));
158 float alphaFade = renderable.particles.m_alphaFade;
159 float sizeModifier = renderable.particles.m_sizeModifier;
160 float texcoordScale = renderable.particles.m_texcoordScale;
161 auto image = renderable.firstImage;
162 if (image && image->m_texture.m_texture) {
163 const auto size = image->m_texture.m_texture->pixelSize();
164 texcoordScale *=
float(size.height()) /
float(size.width());
166 shaders.setUniform(ubufData,
"qt_alphaFade", &alphaFade,
sizeof(
float));
167 shaders.setUniform(ubufData,
"qt_sizeModifier", &sizeModifier,
sizeof(
float));
168 shaders.setUniform(ubufData,
"qt_texcoordScale", &texcoordScale,
sizeof(
float));
214 const QSSGParticleBuffer &buffer,
const QSSGRenderParticles &particles,
215 const QVector3D &cameraDirection,
bool animatedParticles)
217 const QMatrix4x4 &modelMatrix = renderData.getGlobalTransform(particles);
218 const QMatrix4x4 &invModelMatrix = modelMatrix.inverted();
219 QVector3D dir = invModelMatrix.map(cameraDirection);
220 QVector3D n = dir.normalized();
221 const auto segments = buffer.segments();
222 auto particleCount = buffer.particleCount();
223 const bool lineParticles = segments > 0;
225 particleCount /= segments;
226 sortData.resize(particleCount);
229 const auto srcParticlePointer = [](
int line,
int segment,
int sc,
int ss,
int pps,
const char *source) ->
const QSSGLineParticle * {
230 int pi = (line * sc + segment) / pps;
231 int i = (line * sc + segment) % pps;
232 const QSSGLineParticle *sp =
reinterpret_cast<
const QSSGLineParticle *>(source + pi * ss);
238 const auto slices = buffer.sliceCount();
239 const auto ss = buffer.sliceStride();
240 const auto pps = buffer.particlesPerSlice();
243 const char *source = buffer.pointer();
244 const char *begin = source;
247 for (i = 0; i < particleCount; i++) {
249 const QSSGLineParticle *lineBegin = srcParticlePointer(i, 0, segments, ss, pps, source);
251 lineData.d = QVector3D::dotProduct(lineBegin->position, n);
252 for (
int j = 1; j < buffer.segments(); j++) {
253 const QSSGLineParticle *p = srcParticlePointer(i, j, segments, ss, pps, source);
254 lineData.d = qMin(lineData.d, QVector3D::dotProduct(p->position, n));
258 }
else if (animatedParticles) {
259 for (
int s = 0; s < slices; s++) {
260 const QSSGParticleAnimated *sp =
reinterpret_cast<
const QSSGParticleAnimated *>(source);
261 for (
int p = 0; p < pps && i < particleCount; p++) {
262 *dst = { QVector3D::dotProduct(sp->position, n),
int(
reinterpret_cast<
const char *>(sp) - begin)};
270 for (
int s = 0; s < slices; s++) {
271 const QSSGParticleSimple *sp =
reinterpret_cast<
const QSSGParticleSimple *>(source);
272 for (
int p = 0; p < pps && i < particleCount; p++) {
273 *dst = { QVector3D::dotProduct(sp->position, n),
int(
reinterpret_cast<
const char *>(sp) - begin)};
284 result.resize(buffer.bufferSize());
285 std::sort(sortData.begin(), sortData.end(), [](
const QSSGRhiSortData &a,
const QSSGRhiSortData &b){
289 auto copyParticles = [&](QByteArray &dst,
const QList<QSSGRhiSortData> &data,
const QSSGParticleBuffer &buffer) {
290 const auto slices = buffer.sliceCount();
291 const auto ss = buffer.sliceStride();
292 const auto pps = buffer.particlesPerSlice();
294 char *dest = dst.data();
295 const char *source = buffer.pointer();
299 for (
int s = 0; s < slices; s++) {
300 QSSGLineParticle *dp =
reinterpret_cast<QSSGLineParticle *>(dest);
301 for (
int p = 0; p < pps && i < particleCount; p++) {
302 *dp = *srcParticlePointer(sdata
->indexOrOffset, seg, segments, ss, pps, source);
305 if (seg == segments) {
313 }
else if (animatedParticles) {
314 for (
int s = 0; s < slices; s++) {
315 QSSGParticleAnimated *dp =
reinterpret_cast<QSSGParticleAnimated *>(dest);
316 for (
int p = 0; p < pps && i < particleCount; p++) {
317 *dp = *
reinterpret_cast<
const QSSGParticleAnimated *>(source + sdata
->indexOrOffset);
325 for (
int s = 0; s < slices; s++) {
326 QSSGParticleSimple *dp =
reinterpret_cast<QSSGParticleSimple *>(dest);
327 for (
int p = 0; p < pps && i < particleCount; p++) {
328 *dp = *
reinterpret_cast<
const QSSGParticleSimple *>(source + sdata
->indexOrOffset);
339 copyParticles(result, sortData, buffer);
355 QSSGRhiContext *rhiCtx,
356 QSSGRhiGraphicsPipelineState *ps,
357 QSSGParticlesRenderable &renderable,
358 const QSSGLayerRenderData &inData,
359 QRhiRenderPassDescriptor *renderPassDescriptor,
362 QSSGRenderCamera *alteredCamera,
363 QSSGRenderTextureCubeFace cubeFace,
364 QSSGReflectionMapEntry *entry)
366 const void *node = &renderable.particles;
367 const bool needsConversion = !rhiCtx->rhi()->isTextureFormatSupported(QRhiTexture::RGBA32F);
369 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
370 QSSGRhiDrawCallData &dcd = QSSGRhiContextPrivate::get(rhiCtx)->drawCallData({ passKey, node, entry, cubeFaceIdx });
371 shaderPipeline.ensureUniformBuffer(&dcd.ubuf);
373 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
374 if (!alteredCamera) {
375 updateUniformsForParticles(inData, shaderPipeline, rhiCtx, ubufData, renderable, inData.renderedCameras);
377 QSSGRenderCameraList cameras({ alteredCamera });
378 updateUniformsForParticles(inData, shaderPipeline, rhiCtx, ubufData, renderable, cameras);
380 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
382 QSSGRhiParticleData &particleData = QSSGRhiContextPrivate::get(rhiCtx)->particleData(&renderable.particles);
383 const QSSGParticleBuffer &particleBuffer = renderable.particles.m_particleBuffer;
384 int particleCount = particleBuffer.particleCount();
385 if (particleData.texture ==
nullptr || particleData.particleCount != particleCount) {
386 QSize size(particleBuffer.size());
387 if (!particleData.texture) {
388 particleData.texture = rhiCtx->rhi()->newTexture(needsConversion ? QRhiTexture::RGBA16F : QRhiTexture::RGBA32F, size);
389 particleData.texture->create();
391 particleData.texture->setPixelSize(size);
392 particleData.texture->create();
394 particleData.particleCount = particleCount;
397 bool sortingChanged = particleData.sorting != renderable.particles.m_depthSorting;
398 if (sortingChanged && !renderable.particles.m_depthSorting) {
399 particleData.sortData.clear();
400 particleData.sortedData.clear();
402 particleData.sorting = renderable.particles.m_depthSorting;
404 QByteArray uploadData;
406 if (renderable.particles.m_depthSorting) {
407 bool animatedParticles = renderable.particles.m_featureLevel == QSSGRenderParticles::FeatureLevel::Animated;
408 if (!alteredCamera) {
409 sortParticles(inData, particleData.sortedData, particleData.sortData, particleBuffer, renderable.particles, inData.renderedCameraData.value()[0].direction, animatedParticles);
411 const QMatrix4x4 globalTransform = inData.getGlobalTransform(*alteredCamera);
412 sortParticles(inData, particleData.sortedData, particleData.sortData, particleBuffer, renderable.particles, QSSGRenderNode::getScalingCorrectDirection(globalTransform), animatedParticles);
414 uploadData = convertParticleData(particleData.convertData, particleData.sortedData, needsConversion);
416 uploadData = convertParticleData(particleData.convertData, particleBuffer.data(), needsConversion);
419 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
420 QRhiTextureSubresourceUploadDescription upload;
421 upload.setData(uploadData);
422 QRhiTextureUploadDescription uploadDesc(QRhiTextureUploadEntry(0, 0, upload));
423 rub->uploadTexture(particleData.texture, uploadDesc);
424 rhiCtx->commandBuffer()->resourceUpdate(rub);
426 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
427 ia.topology = QRhiGraphicsPipeline::TriangleStrip;
428 ia.inputLayout = QRhiVertexInputLayout();
431 ps->samples = samples;
432 ps->viewCount = viewCount;
433 ps->cullMode = QRhiGraphicsPipeline::None;
435 if (inData.orderIndependentTransparencyEnabled ==
false) {
436 if (renderable.renderableFlags.hasTransparency())
437 fillTargetBlend(ps->targetBlend[0], renderable.particles.m_blendMode);
439 ps->targetBlend[0] = QRhiGraphicsPipeline::TargetBlend();
442 QSSGRhiShaderResourceBindingList bindings;
443 bindings.addUniformBuffer(0, VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline.ub0Size());
447 QSSGRenderableImage *renderableImage = renderable.firstImage;
449 int samplerBinding = shaderPipeline.bindingForTexture(
"qt_sprite");
450 if (samplerBinding >= 0) {
451 QRhiTexture *texture = renderableImage ? renderableImage->m_texture.m_texture :
nullptr;
452 if (samplerBinding >= 0 && texture) {
453 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
454 QRhiSampler *sampler = rhiCtx->sampler({ QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
455 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
456 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
457 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
458 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
459 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
461 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
463 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
464 QRhiTexture *texture = rhiCtx->dummyTexture({}, rub, QSize(4, 4), Qt::white);
465 rhiCtx->commandBuffer()->resourceUpdate(rub);
466 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
467 QRhiSampler::Nearest,
469 QRhiSampler::ClampToEdge,
470 QRhiSampler::ClampToEdge,
473 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
477 samplerBinding = shaderPipeline.bindingForTexture(
"qt_particleTexture");
478 if (samplerBinding >= 0) {
479 QRhiTexture *texture = particleData.texture;
480 if (samplerBinding >= 0 && texture) {
481 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
482 QRhiSampler::Nearest,
484 QRhiSampler::ClampToEdge,
485 QRhiSampler::ClampToEdge,
488 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::VertexStage, texture, sampler);
492 samplerBinding = shaderPipeline.bindingForTexture(
"qt_colorTable");
493 if (samplerBinding >= 0) {
494 bool hasTexture =
false;
495 if (renderable.colorTable) {
496 QRhiTexture *texture = renderable.colorTable->m_texture.m_texture;
499 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
500 QRhiSampler::Nearest,
502 QRhiSampler::ClampToEdge,
503 QRhiSampler::ClampToEdge,
506 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
511 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
512 QRhiTexture *texture = rhiCtx->dummyTexture({}, rub, QSize(4, 4), Qt::white);
513 rhiCtx->commandBuffer()->resourceUpdate(rub);
514 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
515 QRhiSampler::Nearest,
517 QRhiSampler::ClampToEdge,
518 QRhiSampler::ClampToEdge,
521 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
525 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
528 QRhiShaderResourceBindings *&srb = dcd.srb;
529 bool srbChanged =
false;
530 if (!srb || bindings != dcd.bindings) {
531 srb = rhiCtxD->srb(bindings);
532 rhiCtxD->releaseCachedSrb(dcd.bindings);
533 dcd.bindings = bindings;
537 if (cubeFace == QSSGRenderTextureCubeFaceNone)
538 renderable.rhiRenderData.mainPass.srb = srb;
540 renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
542 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
545 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
546 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
549 if (cubeFace == QSSGRenderTextureCubeFaceNone)
550 renderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
552 renderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
554 if (cubeFace == QSSGRenderTextureCubeFaceNone) {
555 renderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
556 renderPassDescriptor,
558 dcd.pipeline = renderable.rhiRenderData.mainPass.pipeline;
560 renderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
561 renderPassDescriptor,
563 dcd.pipeline = renderable.rhiRenderData.reflectionPass.pipeline;
565 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
566 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
572 QSSGRhiContext *rhiCtx,
573 QSSGRhiShaderResourceBindingList &bindings,
574 const QSSGRenderModel *model)
576 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
577 QSSGRhiParticleData &particleData = rhiCtxD->particleData(model);
578 const QSSGParticleBuffer &particleBuffer = *model->particleBuffer;
579 int particleCount = particleBuffer.particleCount();
580 bool update = particleBuffer.serial() != particleData.serial;
581 const bool needsConversion = !rhiCtx->rhi()->isTextureFormatSupported(QRhiTexture::RGBA32F);
582 if (particleData.texture ==
nullptr || particleData.particleCount != particleCount) {
583 QSize size(particleBuffer.size());
584 if (!particleData.texture) {
585 particleData.texture = rhiCtx->rhi()->newTexture(needsConversion ? QRhiTexture::RGBA16F : QRhiTexture::RGBA32F, size);
586 particleData.texture->create();
588 particleData.texture->setPixelSize(size);
589 particleData.texture->create();
591 particleData.particleCount = particleCount;
596 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
597 QRhiTextureSubresourceUploadDescription upload;
598 upload.setData(convertParticleData(particleData.convertData, particleBuffer.data(), needsConversion));
599 QRhiTextureUploadDescription uploadDesc(QRhiTextureUploadEntry(0, 0, upload));
600 rub->uploadTexture(particleData.texture, uploadDesc);
601 rhiCtx->commandBuffer()->resourceUpdate(rub);
603 particleData.serial = particleBuffer.serial();
604 int samplerBinding = shaderPipeline.bindingForTexture(
"qt_particleTexture");
605 if (samplerBinding >= 0) {
606 QRhiTexture *texture = particleData.texture;
607 if (samplerBinding >= 0 && texture) {
608 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
609 QRhiSampler::Nearest,
611 QRhiSampler::ClampToEdge,
612 QRhiSampler::ClampToEdge,
615 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::VertexStage, texture, sampler);
621 QSSGParticlesRenderable &renderable,
622 bool *needsSetViewport,
623 QSSGRenderTextureCubeFace cubeFace,
624 const QSSGRhiGraphicsPipelineState &state)
626 QRhiGraphicsPipeline *ps = renderable.rhiRenderData.mainPass.pipeline;
627 QRhiShaderResourceBindings *srb = renderable.rhiRenderData.mainPass.srb;
629 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
630 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
631 ps = renderable.rhiRenderData.reflectionPass.pipeline;
632 srb = renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx];
638 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
640 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
642 cb->setGraphicsPipeline(ps);
643 cb->setVertexInput(0, 0,
nullptr);
644 cb->setShaderResources(srb);
646 if (needsSetViewport && *needsSetViewport) {
647 cb->setViewport(state.viewport);
648 *needsSetViewport =
false;
650 if (renderable.particles.m_featureLevel >= QSSGRenderParticles::FeatureLevel::Line) {
652 int S = renderable.particles.m_particleBuffer.segments();
653 int N = renderable.particles.m_particleBuffer.particleCount() / S;
656 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderCall, (2 * S | quint64(N) << 32), renderable.particles.profilingId);
659 cb->draw(4, renderable.particles.m_particleBuffer.particleCount());
660 QSSGRHICTX_STAT(rhiCtx, draw(4, renderable.particles.m_particleBuffer.particleCount()));
661 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderCall, (4 | quint64(renderable.particles.m_particleBuffer.particleCount()) << 32), renderable.particles.profilingId);