mirror of
https://github.com/Qz3rK/tdesktop.git
synced 2026-06-02 03:53:42 +02:00
Attempt to fix thanos effect on D3D11.
This commit is contained in:
@@ -20,7 +20,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
constexpr auto kParticleStride = int(24);
|
||||
constexpr auto kQuadVertexCount = int(6);
|
||||
constexpr auto kQuadVertexStride = int(2 * sizeof(float));
|
||||
constexpr auto kComputeWorkgroupSize = int(64);
|
||||
@@ -157,12 +156,6 @@ void ThanosEffectRenderer::initialize(
|
||||
sizeof(RenderUniforms));
|
||||
_renderUniformBuffer->create();
|
||||
|
||||
_placeholderParticleBuffer = rhi->newBuffer(
|
||||
QRhiBuffer::Immutable,
|
||||
QRhiBuffer::VertexBuffer | QRhiBuffer::StorageBuffer,
|
||||
kParticleStride);
|
||||
_placeholderParticleBuffer->create();
|
||||
|
||||
_placeholderTexture = rhi->newTexture(
|
||||
QRhiTexture::RGBA8,
|
||||
QSize(1, 1));
|
||||
@@ -176,6 +169,21 @@ void ThanosEffectRenderer::initialize(
|
||||
QRhiSampler::ClampToEdge);
|
||||
_placeholderSampler->create();
|
||||
|
||||
_placeholderStateTexture = rhi->newTexture(
|
||||
QRhiTexture::RGBA32F,
|
||||
QSize(1, 1),
|
||||
1,
|
||||
QRhiTexture::UsedWithLoadStore);
|
||||
_placeholderStateTexture->create();
|
||||
|
||||
_placeholderStateSampler = rhi->newSampler(
|
||||
QRhiSampler::Nearest,
|
||||
QRhiSampler::Nearest,
|
||||
QRhiSampler::None,
|
||||
QRhiSampler::ClampToEdge,
|
||||
QRhiSampler::ClampToEdge);
|
||||
_placeholderStateSampler->create();
|
||||
|
||||
if (!createPipelines(rt)) {
|
||||
LOG(("ThanosEffect: pipeline creation failed, disabling effect"));
|
||||
_creationFailed = true;
|
||||
@@ -203,14 +211,20 @@ bool ThanosEffectRenderer::createPipelines(QRhiRenderTarget *rt) {
|
||||
|
||||
_computeInitSrbLayout = _rhi->newShaderResourceBindings();
|
||||
_computeInitSrbLayout->setBindings({
|
||||
QRhiShaderResourceBinding::bufferLoadStore(
|
||||
QRhiShaderResourceBinding::imageLoadStore(
|
||||
0,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
_placeholderParticleBuffer),
|
||||
_placeholderStateTexture,
|
||||
0),
|
||||
QRhiShaderResourceBinding::uniformBuffer(
|
||||
1,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
_computeInitUniformBuffer),
|
||||
QRhiShaderResourceBinding::imageLoadStore(
|
||||
2,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
_placeholderStateTexture,
|
||||
0),
|
||||
});
|
||||
_computeInitSrbLayout->create();
|
||||
|
||||
@@ -224,14 +238,20 @@ bool ThanosEffectRenderer::createPipelines(QRhiRenderTarget *rt) {
|
||||
|
||||
_computeUpdateSrbLayout = _rhi->newShaderResourceBindings();
|
||||
_computeUpdateSrbLayout->setBindings({
|
||||
QRhiShaderResourceBinding::bufferLoadStore(
|
||||
QRhiShaderResourceBinding::imageLoadStore(
|
||||
0,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
_placeholderParticleBuffer),
|
||||
_placeholderStateTexture,
|
||||
0),
|
||||
QRhiShaderResourceBinding::uniformBuffer(
|
||||
1,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
_computeUpdateUniformBuffer),
|
||||
QRhiShaderResourceBinding::imageLoadStore(
|
||||
2,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
_placeholderStateTexture,
|
||||
0),
|
||||
});
|
||||
_computeUpdateSrbLayout->create();
|
||||
|
||||
@@ -255,6 +275,11 @@ bool ThanosEffectRenderer::createPipelines(QRhiRenderTarget *rt) {
|
||||
QRhiShaderResourceBinding::FragmentStage,
|
||||
_placeholderTexture,
|
||||
_placeholderSampler),
|
||||
QRhiShaderResourceBinding::sampledTexture(
|
||||
2,
|
||||
QRhiShaderResourceBinding::VertexStage,
|
||||
_placeholderStateTexture,
|
||||
_placeholderStateSampler),
|
||||
});
|
||||
_renderSrbLayout->create();
|
||||
|
||||
@@ -267,13 +292,9 @@ bool ThanosEffectRenderer::createPipelines(QRhiRenderTarget *rt) {
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ quint32(kQuadVertexStride) },
|
||||
{ quint32(kParticleStride),
|
||||
QRhiVertexInputBinding::PerInstance },
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||
{ 1, 1, QRhiVertexInputAttribute::Float2, 0 },
|
||||
{ 1, 2, QRhiVertexInputAttribute::Float, 16 },
|
||||
});
|
||||
_renderPipeline->setVertexInputLayout(inputLayout);
|
||||
|
||||
@@ -450,9 +471,8 @@ void ThanosEffectRenderer::render(
|
||||
|
||||
const QRhiCommandBuffer::VertexInput vbufs[] = {
|
||||
{ _quadVertexBuffer, 0 },
|
||||
{ item.particleBuffer, 0 },
|
||||
};
|
||||
cb->setVertexInput(0, 2, vbufs);
|
||||
cb->setVertexInput(0, 1, vbufs);
|
||||
|
||||
const auto instanceCount =
|
||||
item.particleCountX * item.particleCountY;
|
||||
@@ -544,8 +564,6 @@ ThanosEffectRenderer::AnimatingItem ThanosEffectRenderer::createAnimatingItem(
|
||||
uint32_t(1),
|
||||
uint32_t(maxParticles / float64(result.particleCountY)));
|
||||
}
|
||||
const auto particleCount =
|
||||
result.particleCountX * result.particleCountY;
|
||||
|
||||
auto *tex = _rhi->newTexture(
|
||||
QRhiTexture::RGBA8,
|
||||
@@ -572,16 +590,42 @@ ThanosEffectRenderer::AnimatingItem ThanosEffectRenderer::createAnimatingItem(
|
||||
}
|
||||
result.sampler = sampler;
|
||||
|
||||
auto *particleBuf = _rhi->newBuffer(
|
||||
QRhiBuffer::Static,
|
||||
QRhiBuffer::VertexBuffer | QRhiBuffer::StorageBuffer,
|
||||
particleCount * kParticleStride);
|
||||
if (!particleBuf->create()) {
|
||||
delete particleBuf;
|
||||
auto *stateTex = _rhi->newTexture(
|
||||
QRhiTexture::RGBA32F,
|
||||
QSize(int(result.particleCountX), int(result.particleCountY)),
|
||||
1,
|
||||
QRhiTexture::UsedWithLoadStore);
|
||||
if (!stateTex->create()) {
|
||||
delete stateTex;
|
||||
destroyAnimatingItem(result);
|
||||
return result;
|
||||
}
|
||||
result.particleBuffer = particleBuf;
|
||||
result.particleStateTexture = stateTex;
|
||||
|
||||
auto *velocityTex = _rhi->newTexture(
|
||||
QRhiTexture::RGBA32F,
|
||||
QSize(int(result.particleCountX), int(result.particleCountY)),
|
||||
1,
|
||||
QRhiTexture::UsedWithLoadStore);
|
||||
if (!velocityTex->create()) {
|
||||
delete velocityTex;
|
||||
destroyAnimatingItem(result);
|
||||
return result;
|
||||
}
|
||||
result.particleVelocityTexture = velocityTex;
|
||||
|
||||
auto *stateSampler = _rhi->newSampler(
|
||||
QRhiSampler::Nearest,
|
||||
QRhiSampler::Nearest,
|
||||
QRhiSampler::None,
|
||||
QRhiSampler::ClampToEdge,
|
||||
QRhiSampler::ClampToEdge);
|
||||
if (!stateSampler->create()) {
|
||||
delete stateSampler;
|
||||
destroyAnimatingItem(result);
|
||||
return result;
|
||||
}
|
||||
result.particleStateSampler = stateSampler;
|
||||
|
||||
auto *initUbo = _rhi->newBuffer(
|
||||
QRhiBuffer::Dynamic,
|
||||
@@ -607,14 +651,20 @@ ThanosEffectRenderer::AnimatingItem ThanosEffectRenderer::createAnimatingItem(
|
||||
|
||||
result.computeInitSrb = _rhi->newShaderResourceBindings();
|
||||
result.computeInitSrb->setBindings({
|
||||
QRhiShaderResourceBinding::bufferLoadStore(
|
||||
QRhiShaderResourceBinding::imageLoadStore(
|
||||
0,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
particleBuf),
|
||||
stateTex,
|
||||
0),
|
||||
QRhiShaderResourceBinding::uniformBuffer(
|
||||
1,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
initUbo),
|
||||
QRhiShaderResourceBinding::imageLoadStore(
|
||||
2,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
velocityTex,
|
||||
0),
|
||||
});
|
||||
if (!result.computeInitSrb->create()) {
|
||||
destroyAnimatingItem(result);
|
||||
@@ -623,14 +673,20 @@ ThanosEffectRenderer::AnimatingItem ThanosEffectRenderer::createAnimatingItem(
|
||||
|
||||
result.computeUpdateSrb = _rhi->newShaderResourceBindings();
|
||||
result.computeUpdateSrb->setBindings({
|
||||
QRhiShaderResourceBinding::bufferLoadStore(
|
||||
QRhiShaderResourceBinding::imageLoadStore(
|
||||
0,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
particleBuf),
|
||||
stateTex,
|
||||
0),
|
||||
QRhiShaderResourceBinding::uniformBuffer(
|
||||
1,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
updateUbo),
|
||||
QRhiShaderResourceBinding::imageLoadStore(
|
||||
2,
|
||||
QRhiShaderResourceBinding::ComputeStage,
|
||||
velocityTex,
|
||||
0),
|
||||
});
|
||||
if (!result.computeUpdateSrb->create()) {
|
||||
destroyAnimatingItem(result);
|
||||
@@ -659,6 +715,11 @@ ThanosEffectRenderer::AnimatingItem ThanosEffectRenderer::createAnimatingItem(
|
||||
QRhiShaderResourceBinding::FragmentStage,
|
||||
tex,
|
||||
sampler),
|
||||
QRhiShaderResourceBinding::sampledTexture(
|
||||
2,
|
||||
QRhiShaderResourceBinding::VertexStage,
|
||||
stateTex,
|
||||
stateSampler),
|
||||
});
|
||||
if (!result.renderSrb->create()) {
|
||||
destroyAnimatingItem(result);
|
||||
@@ -681,7 +742,9 @@ void ThanosEffectRenderer::destroyAnimatingItem(AnimatingItem &item) {
|
||||
deferDelete(item.renderUniformBuffer);
|
||||
deferDelete(item.computeUpdateUniformBuffer);
|
||||
deferDelete(item.computeInitUniformBuffer);
|
||||
deferDelete(item.particleBuffer);
|
||||
deferDelete(item.particleStateSampler);
|
||||
deferDelete(item.particleVelocityTexture);
|
||||
deferDelete(item.particleStateTexture);
|
||||
deferDelete(item.sampler);
|
||||
deferDelete(item.texture);
|
||||
item = {};
|
||||
@@ -710,12 +773,14 @@ void ThanosEffectRenderer::releaseResources() {
|
||||
delete _computeInitSrbLayout;
|
||||
_computeInitSrbLayout = nullptr;
|
||||
|
||||
delete _placeholderStateSampler;
|
||||
_placeholderStateSampler = nullptr;
|
||||
delete _placeholderStateTexture;
|
||||
_placeholderStateTexture = nullptr;
|
||||
delete _placeholderSampler;
|
||||
_placeholderSampler = nullptr;
|
||||
delete _placeholderTexture;
|
||||
_placeholderTexture = nullptr;
|
||||
delete _placeholderParticleBuffer;
|
||||
_placeholderParticleBuffer = nullptr;
|
||||
|
||||
delete _renderUniformBuffer;
|
||||
_renderUniformBuffer = nullptr;
|
||||
|
||||
@@ -66,7 +66,9 @@ private:
|
||||
struct AnimatingItem {
|
||||
QRhiTexture *texture = nullptr;
|
||||
QRhiSampler *sampler = nullptr;
|
||||
QRhiBuffer *particleBuffer = nullptr;
|
||||
QRhiTexture *particleStateTexture = nullptr;
|
||||
QRhiTexture *particleVelocityTexture = nullptr;
|
||||
QRhiSampler *particleStateSampler = nullptr;
|
||||
QRhiBuffer *computeInitUniformBuffer = nullptr;
|
||||
QRhiBuffer *computeUpdateUniformBuffer = nullptr;
|
||||
QRhiBuffer *renderUniformBuffer = nullptr;
|
||||
@@ -95,9 +97,10 @@ private:
|
||||
QRhiBuffer *_computeUpdateUniformBuffer = nullptr;
|
||||
QRhiBuffer *_renderUniformBuffer = nullptr;
|
||||
|
||||
QRhiBuffer *_placeholderParticleBuffer = nullptr;
|
||||
QRhiTexture *_placeholderTexture = nullptr;
|
||||
QRhiSampler *_placeholderSampler = nullptr;
|
||||
QRhiTexture *_placeholderStateTexture = nullptr;
|
||||
QRhiSampler *_placeholderStateSampler = nullptr;
|
||||
|
||||
QRhiShaderResourceBindings *_computeInitSrbLayout = nullptr;
|
||||
QRhiShaderResourceBindings *_computeUpdateSrbLayout = nullptr;
|
||||
|
||||
@@ -44,7 +44,13 @@ foreach(_src ${_shader_sources})
|
||||
if("${_ext}" STREQUAL ".comp")
|
||||
set(_glsl_ver "310es,430")
|
||||
else()
|
||||
set(_glsl_ver "100es,120,150")
|
||||
file(READ ${_src} _src_contents)
|
||||
string(FIND "${_src_contents}" "texelFetch" _has_texelfetch)
|
||||
if(NOT _has_texelfetch EQUAL -1)
|
||||
set(_glsl_ver "300es,150")
|
||||
else()
|
||||
set(_glsl_ver "100es,120,150")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
layout(location = 0) in vec2 inQuadPos;
|
||||
|
||||
layout(location = 1) in vec2 inOffset;
|
||||
layout(location = 2) in float inLifetime;
|
||||
|
||||
layout(location = 0) out vec2 v_texcoord;
|
||||
layout(location = 1) out float v_alpha;
|
||||
|
||||
layout(binding = 2) uniform sampler2D particleStateTex;
|
||||
|
||||
layout(std140, binding = 0) uniform Params {
|
||||
vec4 rect;
|
||||
vec2 size;
|
||||
@@ -20,6 +19,13 @@ void main() {
|
||||
uint pX = particleId % particleResolution.x;
|
||||
uint pY = particleId / particleResolution.x;
|
||||
|
||||
vec4 state = texelFetch(
|
||||
particleStateTex,
|
||||
ivec2(int(pX), int(pY)),
|
||||
0);
|
||||
vec2 inOffset = state.xy;
|
||||
float inLifetime = state.z;
|
||||
|
||||
vec2 particleSize = size / vec2(particleResolution);
|
||||
|
||||
vec2 topLeft = vec2(float(pX) * particleSize.x, float(pY) * particleSize.y);
|
||||
|
||||
@@ -2,16 +2,8 @@
|
||||
|
||||
layout(local_size_x = 64) in;
|
||||
|
||||
struct Particle {
|
||||
vec2 offset;
|
||||
vec2 velocity;
|
||||
float lifetime;
|
||||
float _pad;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer Particles {
|
||||
Particle particles[];
|
||||
};
|
||||
layout(rgba32f, binding = 0) uniform image2D particleStateImage;
|
||||
layout(rgba32f, binding = 2) uniform image2D particleVelocityImage;
|
||||
|
||||
layout(std140, binding = 1) uniform Params {
|
||||
uint particleCountX;
|
||||
@@ -45,11 +37,12 @@ void main() {
|
||||
float direction = hashFloat(s) * (3.14159265 * 2.0);
|
||||
float speed = (0.1 + hashFloat(s + 1u) * 0.1) * 320.0;
|
||||
|
||||
Particle p;
|
||||
p.offset = vec2(0.0, 0.0);
|
||||
p.velocity = vec2(cos(direction) * speed, sin(direction) * speed);
|
||||
p.lifetime = 1.5 + hashFloat(s + 2u) * 1.5;
|
||||
p._pad = 0.0;
|
||||
vec2 velocity = vec2(cos(direction) * speed, sin(direction) * speed);
|
||||
float lifetime = 1.5 + hashFloat(s + 2u) * 1.5;
|
||||
|
||||
particles[gid] = p;
|
||||
ivec2 coord = ivec2(
|
||||
int(gid % particleCountX),
|
||||
int(gid / particleCountX));
|
||||
imageStore(particleStateImage, coord, vec4(0.0, 0.0, lifetime, 0.0));
|
||||
imageStore(particleVelocityImage, coord, vec4(velocity, 0.0, 0.0));
|
||||
}
|
||||
|
||||
@@ -2,16 +2,8 @@
|
||||
|
||||
layout(local_size_x = 64) in;
|
||||
|
||||
struct Particle {
|
||||
vec2 offset;
|
||||
vec2 velocity;
|
||||
float lifetime;
|
||||
float _pad;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer Particles {
|
||||
Particle particles[];
|
||||
};
|
||||
layout(rgba32f, binding = 0) uniform image2D particleStateImage;
|
||||
layout(rgba32f, binding = 2) uniform image2D particleVelocityImage;
|
||||
|
||||
layout(std140, binding = 1) uniform Params {
|
||||
uint particleCountX;
|
||||
@@ -43,11 +35,20 @@ void main() {
|
||||
float particleXFraction = float(particleX) / float(particleCountX);
|
||||
float particleFraction = easeInWindow(effectFraction, particleXFraction);
|
||||
|
||||
Particle p = particles[gid];
|
||||
ivec2 coord = ivec2(
|
||||
int(particleX),
|
||||
int(gid / particleCountX));
|
||||
|
||||
p.offset += p.velocity * timeStep * particleFraction;
|
||||
p.velocity.y += 80.0 * timeStep * particleFraction;
|
||||
p.lifetime = max(0.0, p.lifetime - 0.6 * timeStep * particleFraction);
|
||||
vec4 state = imageLoad(particleStateImage, coord);
|
||||
vec2 offset = state.xy;
|
||||
float lifetime = state.z;
|
||||
|
||||
particles[gid] = p;
|
||||
vec2 velocity = imageLoad(particleVelocityImage, coord).xy;
|
||||
|
||||
offset += velocity * timeStep * particleFraction;
|
||||
velocity.y += 80.0 * timeStep * particleFraction;
|
||||
lifetime = max(0.0, lifetime - 0.6 * timeStep * particleFraction);
|
||||
|
||||
imageStore(particleStateImage, coord, vec4(offset, lifetime, 0.0));
|
||||
imageStore(particleVelocityImage, coord, vec4(velocity, 0.0, 0.0));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user