Loading...
Searching...
No Matches
UYVYCompute.hpp
1#pragma once
2#include <Gfx/Graph/Utils.hpp>
4#include <Gfx/Graph/encoders/ComputeEncoder.hpp>
5#include <Gfx/Graph/encoders/GPUVideoEncoder.hpp>
6
7#include <private/qrhi_p.h>
8
9namespace score::gfx
10{
11
21{
22 static constexpr const char* compute_shader = R"_(#version 450
23 layout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;
24
25 layout(binding = 0) uniform sampler2D src_tex;
26 layout(std430, binding = 1) writeonly buffer UyvyBuf {
27 uint uyvy[];
28 };
29 layout(std140, binding = 2) uniform Params {
30 ivec2 src_size;
31 ivec2 _pad0;
32 uint line_stride_words; // bytes-per-row / 4
33 uint pairs_per_row; // == src_width / 2
34 uint _pad1[2];
35 };
36 )_" "%1" R"_(
37
38 uint to_byte(float v) {
39 return uint(clamp(v, 0.0, 1.0) * 255.0 + 0.5);
40 }
41
42 void main() {
43 uint pair_x = gl_GlobalInvocationID.x;
44 uint y = gl_GlobalInvocationID.y;
45 if (pair_x >= pairs_per_row || int(y) >= src_size.y)
46 return;
47
48 #if defined(QSHADER_MSL) || defined(QSHADER_HLSL)
49 int src_y = int(y);
50 #else
51 int src_y = src_size.y - 1 - int(y);
52 #endif
53
54 uint x0 = pair_x * 2u;
55 vec3 a = clamp(convert_from_rgb(texelFetch(src_tex, ivec2(int(x0 ), src_y), 0).rgb), 0.0, 1.0);
56 vec3 b = clamp(convert_from_rgb(texelFetch(src_tex, ivec2(int(x0 + 1u), src_y), 0).rgb), 0.0, 1.0);
57
58 uint Y0 = to_byte(a.x);
59 uint Y1 = to_byte(b.x);
60 uint Cb = to_byte((a.y + b.y) * 0.5);
61 uint Cr = to_byte((a.z + b.z) * 0.5);
62
63 // UYVY little-endian DWORD: Cb, Y0, Cr, Y1
64 uint w = Cb | (Y0 << 8) | (Cr << 16) | (Y1 << 24);
65 uyvy[y * line_stride_words + pair_x] = w;
66 }
67 )_";
68
69 QRhiBuffer* m_paramsUBO{};
70 QRhiSampler* m_sampler{};
71 QRhiShaderResourceBindings* m_srb{};
72 QRhiComputePipeline* m_pipeline{};
73 int m_width{};
74 int m_height{};
75 uint32_t m_pairsPerRow{};
76 uint32_t m_lineStrideBytes{};
77
78 bool init(
79 QRhi& rhi, const RenderState& state, QRhiTexture* inputRGBA, int width,
80 int height, QRhiBuffer* outputBuffer,
81 const QString& colorConversion = colorMatrixOut()) override
82 {
83 if(!outputBuffer || (width % 2) != 0)
84 return false;
85 if(!rhi.isFeatureSupported(QRhi::Compute))
86 return false;
87
88 m_width = width;
89 m_height = height;
90 m_pairsPerRow = width / 2;
91 m_lineStrideBytes = width * 2; // UYVY: 2 bytes per pixel, no padding
92
93 m_paramsUBO = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 32);
94 m_paramsUBO->setName("UYVYComputeEncoder::params");
95 if(!m_paramsUBO->create())
96 return false;
97
98 m_sampler = rhi.newSampler(
99 QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
100 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
101 if(!m_sampler->create())
102 return false;
103
104 m_srb = rhi.newShaderResourceBindings();
105 m_srb->setBindings({
106 QRhiShaderResourceBinding::sampledTexture(
107 0, QRhiShaderResourceBinding::ComputeStage, inputRGBA, m_sampler),
108 QRhiShaderResourceBinding::bufferStore(
109 1, QRhiShaderResourceBinding::ComputeStage, outputBuffer),
110 QRhiShaderResourceBinding::uniformBuffer(
111 2, QRhiShaderResourceBinding::ComputeStage, m_paramsUBO),
112 });
113 if(!m_srb->create())
114 return false;
115
116 QShader cs = makeCompute(
117 state, QString::fromLatin1(compute_shader).arg(colorConversion));
118 m_pipeline = rhi.newComputePipeline();
119 m_pipeline->setShaderStage({QRhiShaderStage::Compute, cs});
120 m_pipeline->setShaderResourceBindings(m_srb);
121 if(!m_pipeline->create())
122 return false;
123
124 return true;
125 }
126
127 void exec(
128 QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch* res) override
129 {
130 struct alignas(16) ParamsData
131 {
132 int32_t srcW, srcH;
133 int32_t pad0[2];
134 uint32_t lineStrideWords;
135 uint32_t pairsPerRow;
136 uint32_t pad1[2];
137 } p{
138 m_width, m_height,
139 {0, 0},
140 m_lineStrideBytes / 4,
141 m_pairsPerRow,
142 {0, 0}};
143 res->updateDynamicBuffer(m_paramsUBO, 0, sizeof(p), &p);
144
145 cb.beginComputePass(res);
146 cb.setComputePipeline(m_pipeline);
147 cb.setShaderResources(m_srb);
148 cb.dispatch((m_pairsPerRow + 31) / 32, m_height, 1);
149 cb.endComputePass();
150 }
151
152 void release() override
153 {
154 delete m_pipeline; m_pipeline = nullptr;
155 delete m_srb; m_srb = nullptr;
156 delete m_sampler; m_sampler = nullptr;
157 delete m_paramsUBO; m_paramsUBO = nullptr;
158 }
159};
160
161} // namespace score::gfx
GPU shader generation for RGB->YUV color space conversion (output/encoding).
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:12
QShader makeCompute(const RenderState &v, QString compute)
Compile a compute shader.
Definition score-plugin-gfx/Gfx/Graph/Utils.cpp:674
Base interface for compute-shader RGBA -> AJA-format encoders.
Definition ComputeEncoder.hpp:36
Global state associated to a rendering context.
Definition RenderState.hpp:37
Compute-shader RGBA -> UYVY (2vuy) encoder targeting an external SSBO.
Definition UYVYCompute.hpp:21