Changeset View
Changeset View
Standalone View
Standalone View
effects/blur/blurshader.cpp
Show All 14 Lines | |||||
15 | * along with this program; see the file COPYING. if not, write to | 15 | * along with this program; see the file COPYING. if not, write to | ||
16 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 16 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
17 | * Boston, MA 02110-1301, USA. | 17 | * Boston, MA 02110-1301, USA. | ||
18 | */ | 18 | */ | ||
19 | 19 | | |||
20 | #include "blurshader.h" | 20 | #include "blurshader.h" | ||
21 | 21 | | |||
22 | #include <kwineffects.h> | 22 | #include <kwineffects.h> | ||
23 | #include "kwinglutils.h" | ||||
23 | #include <kwinglplatform.h> | 24 | #include <kwinglplatform.h> | ||
24 | 25 | | |||
25 | #include <QByteArray> | 26 | #include <QByteArray> | ||
26 | #include <QMatrix4x4> | 27 | #include <QMatrix4x4> | ||
27 | #include <QTextStream> | 28 | #include <QTextStream> | ||
28 | #include <QVector2D> | 29 | #include <QVector2D> | ||
29 | 30 | | |||
30 | #include <cmath> | 31 | #include <cmath> | ||
31 | 32 | | |||
32 | using namespace KWin; | 33 | using namespace KWin; | ||
33 | 34 | | |||
34 | 35 | | |||
35 | BlurShader::BlurShader() | 36 | BlurShader::BlurShader() | ||
36 | : mRadius(0), mValid(false) | 37 | : mValid(false) | ||
37 | { | 38 | { | ||
38 | } | 39 | } | ||
39 | 40 | | |||
40 | BlurShader::~BlurShader() | 41 | BlurShader::~BlurShader() | ||
41 | { | 42 | { | ||
42 | } | 43 | } | ||
43 | 44 | | |||
44 | BlurShader *BlurShader::create() | 45 | BlurShader *BlurShader::create() | ||
45 | { | 46 | { | ||
46 | return new GLSLBlurShader(); | 47 | return new GLSLBlurShader(); | ||
47 | } | 48 | } | ||
48 | 49 | | |||
49 | void BlurShader::setRadius(int radius) | 50 | // ---------------------------------------------------------------------------- | ||
50 | { | 51 | | ||
51 | const int r = qMax(radius, 2); | | |||
52 | 52 | | |||
53 | if (mRadius != r) { | | |||
54 | mRadius = r; | | |||
55 | reset(); | | |||
56 | init(); | | |||
57 | } | | |||
58 | } | | |||
59 | 53 | | |||
60 | void BlurShader::setDirection(Qt::Orientation direction) | 54 | GLSLBlurShader::GLSLBlurShader() | ||
61 | { | 55 | { | ||
62 | mDirection = direction; | 56 | init(); | ||
63 | } | 57 | } | ||
64 | 58 | | |||
zzag: No, it should be in the header file. E.g.
```
...
private:
GLShader *m_shaderDownsample =… | |||||
65 | float BlurShader::gaussian(float x, float sigma) const | 59 | GLSLBlurShader::~GLSLBlurShader() | ||
66 | { | 60 | { | ||
67 | return (1.0 / std::sqrt(2.0 * M_PI) * sigma) | 61 | reset(); | ||
68 | * std::exp(-((x * x) / (2.0 * sigma * sigma))); | | |||
69 | } | 62 | } | ||
70 | 63 | | |||
71 | QList<KernelValue> BlurShader::gaussianKernel() const | 64 | void GLSLBlurShader::reset() | ||
72 | { | 65 | { | ||
73 | int size = qMin(mRadius | 1, maxKernelSize()); | 66 | delete m_shaderDownsample; | ||
74 | if (!(size & 0x1)) | 67 | m_shaderDownsample = nullptr; | ||
75 | size -= 1; | 68 | | ||
69 | delete m_shaderUpsample; | ||||
70 | m_shaderUpsample = nullptr; | ||||
76 | 71 | | |||
77 | QList<KernelValue> kernel; | 72 | delete m_shaderCopysample; | ||
78 | const int center = size / 2; | 73 | m_shaderCopysample = nullptr; | ||
79 | const qreal sigma = (size - 1) / 2.5; | | |||
80 | 74 | | |||
81 | kernel << KernelValue(0.0, gaussian(0.0, sigma)); | 75 | setIsValid(false); | ||
82 | float total = kernel[0].g; | 76 | } | ||
83 | 77 | | |||
84 | for (int x = 1; x <= center; x++) { | 78 | void GLSLBlurShader::setModelViewProjectionMatrix(const QMatrix4x4 &matrix) | ||
85 | const float fx = (x - 1) * 2 + 1.5; | 79 | { | ||
86 | const float g1 = gaussian(fx - 0.5, sigma); | 80 | if (!isValid()) | ||
87 | const float g2 = gaussian(fx + 0.5, sigma); | 81 | return; | ||
88 | 82 | | |||
89 | // Offset taking the contribution of both pixels into account | 83 | switch (m_activeSampleType) { | ||
90 | const float offset = .5 - g1 / (g1 + g2); | 84 | case copySampleType: | ||
85 | if (matrix == m_matrixCopysample) | ||||
86 | return; | ||||
91 | 87 | | |||
92 | kernel << KernelValue(fx + offset, g1 + g2); | 88 | m_matrixCopysample = matrix; | ||
93 | kernel << KernelValue(-(fx + offset), g1 + g2); | 89 | m_shaderCopysample->setUniform(m_mvpMatrixLocationCopysample, matrix); | ||
90 | break; | ||||
94 | 91 | | |||
95 | total += (g1 + g2) * 2; | 92 | case upSampleType: | ||
96 | } | 93 | if (matrix == m_matrixUpsample) | ||
94 | return; | ||||
97 | 95 | | |||
98 | qSort(kernel); | 96 | m_matrixUpsample = matrix; | ||
97 | m_shaderUpsample->setUniform(m_mvpMatrixLocationUpsample, matrix); | ||||
98 | break; | ||||
99 | 99 | | |||
100 | // Normalize the kernel | 100 | case downSampleType: | ||
101 | for (int i = 0; i < kernel.count(); i++) | 101 | if (matrix == m_matrixDownsample) | ||
102 | kernel[i].g /= total; | 102 | return; | ||
103 | 103 | | |||
104 | return kernel; | 104 | m_matrixDownsample = matrix; | ||
105 | m_shaderDownsample->setUniform(m_mvpMatrixLocationDownsample, matrix); | ||||
106 | break; | ||||
107 | } | ||||
105 | } | 108 | } | ||
106 | 109 | | |||
110 | void GLSLBlurShader::setOffset(float offset) | ||||
111 | { | ||||
112 | if (!isValid()) | ||||
113 | return; | ||||
107 | 114 | | |||
115 | switch (m_activeSampleType) { | ||||
116 | case upSampleType: | ||||
117 | if (offset == m_offsetUpsample) | ||||
118 | return; | ||||
108 | 119 | | |||
109 | // ---------------------------------------------------------------------------- | 120 | m_offsetUpsample = offset; | ||
110 | 121 | m_shaderUpsample->setUniform(m_offsetLocationUpsample, offset); | |||
122 | break; | ||||
111 | 123 | | |||
124 | case downSampleType: | ||||
125 | if (offset == m_offsetDownsample) | ||||
126 | return; | ||||
112 | 127 | | |||
113 | GLSLBlurShader::GLSLBlurShader() | 128 | m_offsetDownsample = offset; | ||
You can simplify: GLShader *m_shaderDownsample = nullptr; GLShader *m_shaderUpsample = nullptr; GLShader *m_shaderCopysample = nullptr; zzag: You can simplify:
```
GLShader *m_shaderDownsample = nullptr;
GLShader… | |||||
114 | : BlurShader(), shader(NULL) | 129 | m_shaderDownsample->setUniform(m_offsetLocationDownsample, offset); | ||
115 | { | 130 | break; | ||
116 | } | 131 | } | ||
117 | | ||||
118 | GLSLBlurShader::~GLSLBlurShader() | | |||
119 | { | | |||
120 | reset(); | | |||
121 | } | 132 | } | ||
122 | 133 | | |||
123 | void GLSLBlurShader::reset() | 134 | void GLSLBlurShader::setTextureSize(QSize textureSize) | ||
124 | { | 135 | { | ||
125 | delete shader; | 136 | if (!isValid()) | ||
126 | shader = NULL; | 137 | return; | ||
127 | 138 | | |||
128 | setIsValid(false); | 139 | QVector2D texSize = QVector2D(textureSize.width(), textureSize.height()); | ||
129 | } | | |||
130 | 140 | | |||
zzag: `nullptr` | |||||
131 | void GLSLBlurShader::setPixelDistance(float val) | 141 | switch (m_activeSampleType) { | ||
132 | { | 142 | case copySampleType: | ||
133 | if (!isValid()) | 143 | if (textureSize == m_textureSizeCopysample) | ||
zzag: `nullptr` | |||||
134 | return; | 144 | return; | ||
135 | 145 | | |||
136 | QVector2D pixelSize(0.0, 0.0); | 146 | m_textureSizeCopysample = textureSize; | ||
zzag: `nullptr` | |||||
137 | if (direction() == Qt::Horizontal) | 147 | m_shaderCopysample->setUniform(m_textureSizeLocationCopysample, texSize); | ||
138 | pixelSize.setX(val); | 148 | break; | ||
139 | else | | |||
140 | pixelSize.setY(val); | | |||
141 | 149 | | |||
142 | shader->setUniform(pixelSizeLocation, pixelSize); | 150 | case upSampleType: | ||
143 | } | 151 | if (textureSize == m_textureSizeUpsample) | ||
152 | return; | ||||
144 | 153 | | |||
145 | void GLSLBlurShader::setTextureMatrix(const QMatrix4x4 &matrix) | 154 | m_textureSizeUpsample = textureSize; | ||
146 | { | 155 | m_shaderUpsample->setUniform(m_textureSizeLocationUpsample, texSize); | ||
147 | if (!isValid()) | 156 | break; | ||
zzag: Please use `{}` | |||||
Most other if statements don't use brackets when there is only a return line and I don't intend to break that tradition, or I might have to correct all of them too. anemeth: Most other if statements don't use brackets when there is only a return line and I don't intend… | |||||
157 | | ||||
158 | case downSampleType: | ||||
159 | if (textureSize == m_textureSizeDownsample) | ||||
148 | return; | 160 | return; | ||
149 | 161 | | |||
150 | shader->setUniform(textureMatrixLocation, matrix); | 162 | m_textureSizeDownsample = textureSize; | ||
163 | m_shaderDownsample->setUniform(m_textureSizeLocationDownsample, texSize); | ||||
164 | break; | ||||
165 | } | ||||
151 | } | 166 | } | ||
152 | 167 | | |||
153 | void GLSLBlurShader::setModelViewProjectionMatrix(const QMatrix4x4 &matrix) | 168 | void GLSLBlurShader::setBlurRect(QRect blurRect, QSize screenSize) | ||
154 | { | 169 | { | ||
155 | if (!isValid()) | 170 | if (!isValid() || blurRect == m_blurRectCopysample) | ||
156 | return; | 171 | return; | ||
157 | 172 | | |||
158 | shader->setUniform(mvpMatrixLocation, matrix); | 173 | m_blurRectCopysample = blurRect; | ||
174 | | ||||
175 | QVector4D rect = QVector4D( | ||||
176 | blurRect.bottomLeft().x() / float(screenSize.width()), | ||||
177 | 1.0 - blurRect.bottomLeft().y() / float(screenSize.height()), | ||||
178 | blurRect.topRight().x() / float(screenSize.width()), | ||||
179 | 1.0 - blurRect.topRight().y() / float(screenSize.height()) | ||||
180 | ); | ||||
181 | | ||||
182 | m_shaderCopysample->setUniform(m_blurRectLocationCopysample, rect); | ||||
159 | } | 183 | } | ||
160 | 184 | | |||
161 | void GLSLBlurShader::bind() | 185 | void GLSLBlurShader::bind(int sampleType) | ||
162 | { | 186 | { | ||
163 | if (!isValid()) | 187 | if (!isValid()) | ||
164 | return; | 188 | return; | ||
165 | 189 | | |||
166 | ShaderManager::instance()->pushShader(shader); | 190 | switch (sampleType) { | ||
191 | case copySampleType: | ||||
192 | ShaderManager::instance()->pushShader(m_shaderCopysample); | ||||
193 | break; | ||||
194 | | ||||
195 | case upSampleType: | ||||
196 | ShaderManager::instance()->pushShader(m_shaderUpsample); | ||||
197 | break; | ||||
198 | | ||||
199 | case downSampleType: | ||||
200 | ShaderManager::instance()->pushShader(m_shaderDownsample); | ||||
201 | break; | ||||
167 | } | 202 | } | ||
168 | 203 | | |||
169 | void GLSLBlurShader::unbind() | 204 | m_activeSampleType = sampleType; | ||
170 | { | | |||
171 | ShaderManager::instance()->popShader(); | | |||
172 | } | 205 | } | ||
173 | 206 | | |||
174 | int GLSLBlurShader::maxKernelSize() const | 207 | void GLSLBlurShader::unbind() | ||
175 | { | 208 | { | ||
176 | if (GLPlatform::instance()->isGLES()) { | 209 | ShaderManager::instance()->popShader(); | ||
177 | // GL_MAX_VARYING_FLOATS not available in GLES | | |||
178 | // querying for GL_MAX_VARYING_VECTORS crashes on nouveau | | |||
179 | // using the minimum value of 8 | | |||
180 | return 8 * 2; | | |||
181 | } else { | | |||
182 | int value; | | |||
183 | glGetIntegerv(GL_MAX_VARYING_FLOATS, &value); | | |||
184 | // Maximum number of vec4 varyings * 2 | | |||
185 | // The code generator will pack two vec2's into each vec4. | | |||
186 | return value / 2; | | |||
187 | } | | |||
188 | } | 210 | } | ||
189 | 211 | | |||
190 | void GLSLBlurShader::init() | 212 | void GLSLBlurShader::init() | ||
191 | { | 213 | { | ||
192 | QList<KernelValue> kernel = gaussianKernel(); | | |||
193 | const int size = kernel.size(); | | |||
194 | const int center = size / 2; | | |||
195 | | ||||
196 | QList<QVector4D> offsets; | | |||
197 | for (int i = 0; i < kernel.size(); i += 2) { | | |||
198 | QVector4D vec4(0, 0, 0, 0); | | |||
199 | | ||||
200 | vec4.setX(kernel[i].x); | | |||
201 | vec4.setY(kernel[i].x); | | |||
202 | | ||||
203 | if (i < kernel.size() - 1) { | | |||
204 | vec4.setZ(kernel[i + 1].x); | | |||
205 | vec4.setW(kernel[i + 1].x); | | |||
206 | } | | |||
207 | | ||||
208 | offsets << vec4; | | |||
209 | } | | |||
210 | | ||||
211 | const bool gles = GLPlatform::instance()->isGLES(); | 214 | const bool gles = GLPlatform::instance()->isGLES(); | ||
212 | const bool glsl_140 = !gles && GLPlatform::instance()->glslVersion() >= kVersionNumber(1, 40); | 215 | const bool glsl_140 = !gles && GLPlatform::instance()->glslVersion() >= kVersionNumber(1, 40); | ||
213 | const bool core = glsl_140 || (gles && GLPlatform::instance()->glslVersion() >= kVersionNumber(3, 0)); | 216 | const bool core = glsl_140 || (gles && GLPlatform::instance()->glslVersion() >= kVersionNumber(3, 0)); | ||
214 | 217 | | |||
215 | QByteArray vertexSource; | 218 | QByteArray vertexSource; | ||
216 | QByteArray fragmentSource; | 219 | QByteArray fragmentDownSource; | ||
220 | QByteArray fragmentUpSource; | ||||
221 | QByteArray fragmentCopySource; | ||||
217 | 222 | | |||
218 | const QByteArray attribute = core ? "in" : "attribute"; | 223 | const QByteArray attribute = core ? "in" : "attribute"; | ||
219 | const QByteArray varying_in = core ? (gles ? "in" : "noperspective in") : "varying"; | | |||
220 | const QByteArray varying_out = core ? (gles ? "out" : "noperspective out") : "varying"; | | |||
221 | const QByteArray texture2D = core ? "texture" : "texture2D"; | 224 | const QByteArray texture2D = core ? "texture" : "texture2D"; | ||
222 | const QByteArray fragColor = core ? "fragColor" : "gl_FragColor"; | 225 | const QByteArray fragColor = core ? "fragColor" : "gl_FragColor"; | ||
223 | 226 | | |||
224 | // Vertex shader | 227 | QString glHeaderString; | ||
225 | // =================================================================== | | |||
226 | QTextStream stream(&vertexSource); | | |||
227 | 228 | | |||
228 | if (gles) { | 229 | if (gles) { | ||
229 | if (core) { | 230 | if (core) { | ||
230 | stream << "#version 300 es\n\n"; | 231 | glHeaderString += "#version 300 es\n\n"; | ||
231 | } | 232 | } | ||
232 | stream << "precision highp float;\n"; | 233 | | ||
234 | glHeaderString += "precision highp float;\n"; | ||||
233 | } else if (glsl_140) { | 235 | } else if (glsl_140) { | ||
234 | stream << "#version 140\n\n"; | 236 | glHeaderString += "#version 140\n\n"; | ||
QString glHeaderString; if (gles) { if (core) { glHeaderString += "#version 300 es\n\n"; } glHeaderString += "precision highp float;\n"; } else if (glsl_140) { glHeaderString += "#version 140\n\n"; } streamVert << glHeaderString; anthonyfieroni: ```
QString glHeaderString;
if (gles) {
if (core) {
glHeaderString += "#version 300… | |||||
235 | } | 237 | } | ||
236 | 238 | | |||
237 | stream << "uniform mat4 modelViewProjectionMatrix;\n"; | 239 | QString glUniformString = "uniform sampler2D texUnit;\n" | ||
238 | stream << "uniform mat4 textureMatrix;\n"; | 240 | "uniform float offset;\n" | ||
239 | stream << "uniform vec2 pixelSize;\n\n"; | 241 | "uniform vec2 textureSize;\n"; | ||
textureSize is also the name of a built-in function in GLSL, so I suggest changing the name to targetSize, renderTargetSize, framebufferSize or something similar. That also makes it clear that it is not the size of the texture being sampled. fredrik: textureSize is also the name of a built-in function in GLSL, so I suggest changing the name to… | |||||
240 | stream << attribute << " vec4 vertex;\n\n"; | | |||
241 | stream << varying_out << " vec4 samplePos[" << std::ceil(size / 2.0) << "];\n"; | | |||
242 | stream << "\n"; | | |||
243 | stream << "void main(void)\n"; | | |||
244 | stream << "{\n"; | | |||
245 | stream << " vec4 center = vec4(textureMatrix * vertex).stst;\n"; | | |||
246 | stream << " vec4 ps = pixelSize.stst;\n\n"; | | |||
247 | for (int i = 0; i < offsets.size(); i++) { | | |||
248 | stream << " samplePos[" << i << "] = center + ps * vec4(" | | |||
249 | << offsets[i].x() << ", " << offsets[i].y() << ", " | | |||
250 | << offsets[i].z() << ", " << offsets[i].w() << ");\n"; | | |||
251 | } | | |||
252 | stream << "\n"; | | |||
253 | stream << " gl_Position = modelViewProjectionMatrix * vertex;\n"; | | |||
254 | stream << "}\n"; | | |||
255 | stream.flush(); | | |||
256 | 242 | | |||
257 | // Fragment shader | | |||
258 | // =================================================================== | | |||
259 | QTextStream stream2(&fragmentSource); | | |||
260 | | ||||
261 | if (gles) { | | |||
262 | if (core) { | 243 | if (core) { | ||
263 | stream2 << "#version 300 es\n\n"; | 244 | glUniformString += "out vec4 fragColor;\n\n"; | ||
264 | } | | |||
265 | stream2 << "precision highp float;\n"; | | |||
266 | } else if (glsl_140) { | | |||
267 | stream2 << "#version 140\n\n"; | | |||
268 | } | 245 | } | ||
269 | 246 | | |||
270 | stream2 << "uniform sampler2D texUnit;\n"; | | |||
271 | stream2 << varying_in << " vec4 samplePos[" << std::ceil(size / 2.0) << "];\n\n"; | | |||
272 | 247 | | |||
273 | for (int i = 0; i <= center; i++) | 248 | // Vertex shader | ||
274 | stream2 << "const float kernel" << i << " = " << kernel[i].g << ";\n"; | 249 | // =================================================================== | ||
QString glUniformString = "uniform sampler2D texUnit;\n" "uniform float offset;\n" "uniform vec2 textureSize;\n"; if (core) { glUniformString += "out vec4 fragColor;\n\n"; } streamFragDown << glUniformString; anthonyfieroni: ```
QString glUniformString = "uniform sampler2D texUnit;\n"
"uniform… | |||||
275 | stream2 << "\n"; | 250 | QTextStream streamVert(&vertexSource); | ||
251 | | ||||
252 | streamVert << glHeaderString; | ||||
253 | | ||||
254 | streamVert << "uniform mat4 modelViewProjectionMatrix;\n"; | ||||
255 | streamVert << attribute << " vec4 vertex;\n\n"; | ||||
256 | streamVert << "\n"; | ||||
257 | streamVert << "void main(void)\n"; | ||||
258 | streamVert << "{\n"; | ||||
259 | streamVert << " gl_Position = modelViewProjectionMatrix * vertex;\n"; | ||||
260 | streamVert << "}\n"; | ||||
261 | | ||||
anthonyfieroni: ```
streamFragDown << glHeaderString;
``` | |||||
262 | streamVert.flush(); | ||||
263 | | ||||
264 | // Fragment shader (Dual Kawase Blur) - Downsample | ||||
265 | // =================================================================== | ||||
266 | QTextStream streamFragDown(&fragmentDownSource); | ||||
267 | | ||||
268 | streamFragDown << glHeaderString << glUniformString; | ||||
269 | | ||||
270 | streamFragDown << "void main(void)\n"; | ||||
271 | streamFragDown << "{\n"; | ||||
272 | streamFragDown << " vec2 uv = vec2(gl_FragCoord.xy / textureSize);\n"; | ||||
273 | streamFragDown << " vec2 halfpixel = vec2(0.5 / textureSize);\n"; | ||||
274 | streamFragDown << " \n"; | ||||
275 | streamFragDown << " vec4 sum = " << texture2D << "(texUnit, uv) * 4.0;\n"; | ||||
276 | streamFragDown << " sum += " << texture2D << "(texUnit, uv - halfpixel.xy * offset);\n"; | ||||
277 | streamFragDown << " sum += " << texture2D << "(texUnit, uv + halfpixel.xy * offset);\n"; | ||||
278 | streamFragDown << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x, -halfpixel.y) * offset);\n"; | ||||
279 | streamFragDown << " sum += " << texture2D << "(texUnit, uv - vec2(halfpixel.x, -halfpixel.y) * offset);\n"; | ||||
280 | streamFragDown << " \n"; | ||||
281 | streamFragDown << " " << fragColor << " = sum / 8.0;\n"; | ||||
282 | streamFragDown << "}\n"; | ||||
283 | | ||||
284 | streamFragDown.flush(); | ||||
285 | | ||||
286 | // Fragment shader (Dual Kawase Blur) - Upsample | ||||
287 | // =================================================================== | ||||
288 | QTextStream streamFragUp(&fragmentUpSource); | ||||
289 | | ||||
290 | streamFragUp << glHeaderString << glUniformString; | ||||
291 | | ||||
292 | streamFragUp << "void main(void)\n"; | ||||
293 | streamFragUp << "{\n"; | ||||
294 | streamFragUp << " vec2 uv = vec2(gl_FragCoord.xy / textureSize);\n"; | ||||
295 | streamFragUp << " vec2 halfpixel = vec2(0.5 / textureSize);\n"; | ||||
296 | streamFragUp << " \n"; | ||||
297 | streamFragUp << " vec4 sum = " << texture2D << "(texUnit, uv + vec2(-halfpixel.x * 2.0, 0.0) * offset);\n"; | ||||
298 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(-halfpixel.x, halfpixel.y) * offset) * 2.0;\n"; | ||||
299 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(0.0, halfpixel.y * 2.0) * offset);\n"; | ||||
300 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x, halfpixel.y) * offset) * 2.0;\n"; | ||||
301 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x * 2.0, 0.0) * offset);\n"; | ||||
302 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x, -halfpixel.y) * offset) * 2.0;\n"; | ||||
303 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(0.0, -halfpixel.y * 2.0) * offset);\n"; | ||||
304 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(-halfpixel.x, -halfpixel.y) * offset) * 2.0;\n"; | ||||
305 | streamFragUp << " \n"; | ||||
306 | streamFragUp << " " << fragColor << " = sum / 12.0;\n"; | ||||
307 | streamFragUp << "}\n"; | ||||
308 | | ||||
309 | streamFragUp.flush(); | ||||
310 | | ||||
311 | // Fragment shader - Copy texture | ||||
312 | // =================================================================== | ||||
313 | QTextStream streamFragCopy(&fragmentCopySource); | ||||
314 | | ||||
315 | streamFragCopy << glHeaderString; | ||||
316 | | ||||
317 | streamFragCopy << "uniform sampler2D texUnit;\n"; | ||||
318 | streamFragCopy << "uniform vec2 textureSize;\n"; | ||||
319 | streamFragCopy << "uniform vec4 blurRect;\n"; | ||||
276 | 320 | | |||
anthonyfieroni: ```
streamFragUp << glHeaderString << glUniformString;
``` | |||||
277 | if (core) | 321 | if (core) | ||
278 | stream2 << "out vec4 fragColor;\n\n"; | 322 | streamFragCopy << "out vec4 fragColor;\n\n"; | ||
323 | | ||||
324 | streamFragCopy << "void main(void)\n"; | ||||
325 | streamFragCopy << "{\n"; | ||||
326 | streamFragCopy << " vec2 uv = vec2(gl_FragCoord.xy / textureSize);\n"; | ||||
327 | streamFragCopy << " " << fragColor << " = " << texture2D << "(texUnit, clamp(uv, blurRect.xy, blurRect.zw));\n"; | ||||
328 | streamFragCopy << "}\n"; | ||||
279 | 329 | | |||
280 | stream2 << "void main(void)\n"; | 330 | streamFragCopy.flush(); | ||
281 | stream2 << "{\n"; | 331 | | ||
282 | stream2 << " vec4 sum = " << texture2D << "(texUnit, samplePos[0].st) * kernel0;\n"; | 332 | | ||
283 | for (int i = 1, j = -center + 1; i < size; i++, j++) | 333 | m_shaderDownsample = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentDownSource); | ||
284 | stream2 << " sum = sum + " << texture2D << "(texUnit, samplePos[" << i / 2 | 334 | m_shaderUpsample = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentUpSource); | ||
285 | << ((i % 2) ? "].pq)" : "].st)") << " * kernel" << center - qAbs(j) << ";\n"; | 335 | m_shaderCopysample = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentCopySource); | ||
286 | stream2 << " " << fragColor << " = sum;\n"; | 336 | | ||
287 | stream2 << "}\n"; | 337 | bool areShadersValid = m_shaderDownsample->isValid() && m_shaderUpsample->isValid() && m_shaderCopysample->isValid(); | ||
288 | stream2.flush(); | 338 | setIsValid(areShadersValid); | ||
289 | 339 | | |||
290 | shader = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentSource); | 340 | if (areShadersValid) { | ||
291 | if (shader->isValid()) { | 341 | m_mvpMatrixLocationDownsample = m_shaderDownsample->uniformLocation("modelViewProjectionMatrix"); | ||
292 | pixelSizeLocation = shader->uniformLocation("pixelSize"); | 342 | m_offsetLocationDownsample = m_shaderDownsample->uniformLocation("offset"); | ||
293 | textureMatrixLocation = shader->uniformLocation("textureMatrix"); | 343 | m_textureSizeLocationDownsample = m_shaderDownsample->uniformLocation("textureSize"); | ||
294 | mvpMatrixLocation = shader->uniformLocation("modelViewProjectionMatrix"); | 344 | | ||
345 | m_mvpMatrixLocationUpsample = m_shaderUpsample->uniformLocation("modelViewProjectionMatrix"); | ||||
346 | m_offsetLocationUpsample = m_shaderUpsample->uniformLocation("offset"); | ||||
347 | m_textureSizeLocationUpsample = m_shaderUpsample->uniformLocation("textureSize"); | ||||
348 | | ||||
349 | m_mvpMatrixLocationCopysample = m_shaderCopysample->uniformLocation("modelViewProjectionMatrix"); | ||||
350 | m_textureSizeLocationCopysample = m_shaderCopysample->uniformLocation("textureSize"); | ||||
351 | m_blurRectLocationCopysample = m_shaderCopysample->uniformLocation("blurRect"); | ||||
295 | 352 | | |||
296 | QMatrix4x4 modelViewProjection; | 353 | QMatrix4x4 modelViewProjection; | ||
297 | const QSize screenSize = effects->virtualScreenSize(); | 354 | const QSize screenSize = effects->virtualScreenSize(); | ||
298 | modelViewProjection.ortho(0, screenSize.width(), screenSize.height(), 0, 0, 65535); | 355 | modelViewProjection.ortho(0, screenSize.width(), screenSize.height(), 0, 0, 65535); | ||
299 | ShaderManager::instance()->pushShader(shader); | 356 | | ||
300 | shader->setUniform(textureMatrixLocation, QMatrix4x4()); | 357 | //Add default values to the uniforms of the shaders | ||
301 | shader->setUniform(mvpMatrixLocation, modelViewProjection); | 358 | ShaderManager::instance()->pushShader(m_shaderDownsample); | ||
anthonyfieroni: ```
streamFragCopy << glHeaderString << glUniformString;
``` | |||||
359 | m_shaderDownsample->setUniform(m_mvpMatrixLocationDownsample, modelViewProjection); | ||||
360 | m_shaderDownsample->setUniform(m_offsetLocationDownsample, float(1.0)); | ||||
361 | m_shaderDownsample->setUniform(m_textureSizeLocationDownsample, QVector2D(1.0, 1.0)); | ||||
362 | ShaderManager::instance()->popShader(); | ||||
363 | | ||||
364 | ShaderManager::instance()->pushShader(m_shaderUpsample); | ||||
365 | m_shaderUpsample->setUniform(m_mvpMatrixLocationUpsample, modelViewProjection); | ||||
366 | m_shaderUpsample->setUniform(m_offsetLocationUpsample, float(1.0)); | ||||
367 | m_shaderUpsample->setUniform(m_textureSizeLocationUpsample, QVector2D(1.0, 1.0)); | ||||
302 | ShaderManager::instance()->popShader(); | 368 | ShaderManager::instance()->popShader(); | ||
303 | } | | |||
304 | 369 | | |||
305 | setIsValid(shader->isValid()); | 370 | ShaderManager::instance()->pushShader(m_shaderCopysample); | ||
371 | m_shaderCopysample->setUniform(m_mvpMatrixLocationCopysample, modelViewProjection); | ||||
372 | m_shaderCopysample->setUniform(m_textureSizeLocationCopysample, QVector2D(1.0, 1.0)); | ||||
373 | m_shaderCopysample->setUniform(m_blurRectLocationCopysample, QVector4D(1.0, 1.0, 1.0, 1.0)); | ||||
374 | ShaderManager::instance()->popShader(); | ||||
375 | | ||||
376 | m_activeSampleType = -1; | ||||
377 | } | ||||
306 | } | 378 | } |
No, it should be in the header file. E.g.