1 /* 2 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. 3 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. 4 * Copyright (C) 2012 Company 100, Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above 11 * copyright notice, this list of conditions and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials 16 * provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include "config.h" 33 34 #include "core/platform/graphics/filters/custom/CustomFilterRenderer.h" 35 36 #include "core/platform/graphics/GraphicsContext3D.h" 37 #include "core/platform/graphics/filters/custom/CustomFilterArrayParameter.h" 38 #include "core/platform/graphics/filters/custom/CustomFilterCompiledProgram.h" 39 #include "core/platform/graphics/filters/custom/CustomFilterConstants.h" 40 #include "core/platform/graphics/filters/custom/CustomFilterMesh.h" 41 #include "core/platform/graphics/filters/custom/CustomFilterNumberParameter.h" 42 #include "core/platform/graphics/filters/custom/CustomFilterParameter.h" 43 #include "core/platform/graphics/filters/custom/CustomFilterTransformParameter.h" 44 #include "core/platform/graphics/transforms/TransformationMatrix.h" 45 46 namespace WebCore { 47 48 static void orthogonalProjectionMatrix(TransformationMatrix& matrix, float left, float right, float bottom, float top) 49 { 50 ASSERT(matrix.isIdentity()); 51 52 float deltaX = right - left; 53 float deltaY = top - bottom; 54 if (!deltaX || !deltaY) 55 return; 56 matrix.setM11(2.0f / deltaX); 57 matrix.setM41(-(right + left) / deltaX); 58 matrix.setM22(2.0f / deltaY); 59 matrix.setM42(-(top + bottom) / deltaY); 60 61 // Use big enough near/far values, so that simple rotations of rather large objects will not 62 // get clipped. 10000 should cover most of the screen resolutions. 63 const float farValue = 10000; 64 const float nearValue = -10000; 65 matrix.setM33(-2.0f / (farValue - nearValue)); 66 matrix.setM43(- (farValue + nearValue) / (farValue - nearValue)); 67 matrix.setM44(1.0f); 68 } 69 70 PassRefPtr<CustomFilterRenderer> CustomFilterRenderer::create(PassRefPtr<GraphicsContext3D> context, CustomFilterProgramType programType, const CustomFilterParameterList& parameters, 71 unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) 72 { 73 return adoptRef(new CustomFilterRenderer(context, programType, parameters, meshRows, meshColumns, meshType)); 74 } 75 76 CustomFilterRenderer::CustomFilterRenderer(PassRefPtr<GraphicsContext3D> context, CustomFilterProgramType programType, const CustomFilterParameterList& parameters, 77 unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) 78 : m_context(context) 79 , m_programType(programType) 80 , m_parameters(parameters) 81 , m_meshRows(meshRows) 82 , m_meshColumns(meshColumns) 83 , m_meshType(meshType) 84 { 85 } 86 87 CustomFilterRenderer::~CustomFilterRenderer() 88 { 89 } 90 91 bool CustomFilterRenderer::premultipliedAlpha() const 92 { 93 return m_programType == PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE; 94 } 95 96 bool CustomFilterRenderer::programNeedsInputTexture() const 97 { 98 ASSERT(m_compiledProgram.get()); 99 return m_compiledProgram->samplerLocation() != -1; 100 } 101 102 void CustomFilterRenderer::draw(Platform3DObject inputTexture, const IntSize& size) 103 { 104 // FIXME: We would need something like CustomFilterRendererState that will contain the size and other parameters in the future. We should pass that to bindProgramBuffers instead of storing it. 105 // https://bugs.webkit.org/show_bug.cgi?id=100107 106 m_contextSize = size; 107 108 bindProgramAndBuffers(inputTexture); 109 m_context->drawElements(GraphicsContext3D::TRIANGLES, m_mesh->indicesCount(), GraphicsContext3D::UNSIGNED_SHORT, 0); 110 unbindVertexAttributes(); 111 } 112 113 void CustomFilterRenderer::setCompiledProgram(PassRefPtr<CustomFilterCompiledProgram> compiledProgram) 114 { 115 m_compiledProgram = compiledProgram; 116 } 117 118 bool CustomFilterRenderer::prepareForDrawing() 119 { 120 m_context->makeContextCurrent(); 121 if (!m_compiledProgram || !m_compiledProgram->isInitialized()) 122 return false; 123 initializeMeshIfNeeded(); 124 return true; 125 } 126 127 void CustomFilterRenderer::initializeMeshIfNeeded() 128 { 129 if (m_mesh.get()) 130 return; 131 132 // FIXME: Sharing the mesh would just save the time needed to upload it to the GPU, so I assume we could 133 // benchmark that for performance. 134 // https://bugs.webkit.org/show_bug.cgi?id=88429 135 m_mesh = CustomFilterMesh::create(m_context.get(), m_meshColumns, m_meshRows, FloatRect(0, 0, 1, 1), m_meshType); 136 } 137 138 void CustomFilterRenderer::bindVertexAttribute(int attributeLocation, unsigned size, unsigned offset) 139 { 140 if (attributeLocation != -1) { 141 m_context->vertexAttribPointer(attributeLocation, size, GraphicsContext3D::FLOAT, false, m_mesh->bytesPerVertex(), offset); 142 m_context->enableVertexAttribArray(attributeLocation); 143 } 144 } 145 146 void CustomFilterRenderer::unbindVertexAttribute(int attributeLocation) 147 { 148 if (attributeLocation != -1) 149 m_context->disableVertexAttribArray(attributeLocation); 150 } 151 152 void CustomFilterRenderer::bindProgramArrayParameters(int uniformLocation, CustomFilterArrayParameter* arrayParameter) 153 { 154 unsigned parameterSize = arrayParameter->size(); 155 Vector<GC3Dfloat> floatVector; 156 157 for (unsigned i = 0; i < parameterSize; ++i) 158 floatVector.append(arrayParameter->valueAt(i)); 159 160 m_context->uniform1fv(uniformLocation, parameterSize, floatVector.data()); 161 } 162 163 void CustomFilterRenderer::bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter* numberParameter) 164 { 165 switch (numberParameter->size()) { 166 case 1: 167 m_context->uniform1f(uniformLocation, numberParameter->valueAt(0)); 168 break; 169 case 2: 170 m_context->uniform2f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1)); 171 break; 172 case 3: 173 m_context->uniform3f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2)); 174 break; 175 case 4: 176 m_context->uniform4f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2), numberParameter->valueAt(3)); 177 break; 178 default: 179 ASSERT_NOT_REACHED(); 180 } 181 } 182 183 void CustomFilterRenderer::bindProgramTransformParameter(int uniformLocation, CustomFilterTransformParameter* transformParameter) 184 { 185 TransformationMatrix matrix; 186 if (m_contextSize.width() && m_contextSize.height()) { 187 // The viewport is a box with the size of 1 unit, so we are scaling up here to make sure that translations happen using real pixel 188 // units. At the end we scale back down in order to map it back to the original box. Note that transforms come in reverse order, because it is 189 // supposed to multiply to the left of the coordinates of the vertices. 190 // Note that the origin (0, 0) of the viewport is in the middle of the context, so there's no need to change the origin of the transform 191 // in order to rotate around the middle of mesh. 192 matrix.scale3d(1.0 / m_contextSize.width(), 1.0 / m_contextSize.height(), 1); 193 transformParameter->applyTransform(matrix, m_contextSize); 194 matrix.scale3d(m_contextSize.width(), m_contextSize.height(), 1); 195 } 196 float glMatrix[16]; 197 matrix.toColumnMajorFloatArray(glMatrix); 198 m_context->uniformMatrix4fv(uniformLocation, 1, false, &glMatrix[0]); 199 } 200 201 void CustomFilterRenderer::bindProgramParameters() 202 { 203 // FIXME: Find a way to reset uniforms that are not specified in CSS. This is needed to avoid using values 204 // set by other previous rendered filters. 205 // https://bugs.webkit.org/show_bug.cgi?id=76440 206 207 size_t parametersSize = m_parameters.size(); 208 for (size_t i = 0; i < parametersSize; ++i) { 209 CustomFilterParameter* parameter = m_parameters.at(i).get(); 210 int uniformLocation = m_compiledProgram->uniformLocationByName(parameter->name()); 211 if (uniformLocation == -1) 212 continue; 213 switch (parameter->parameterType()) { 214 case CustomFilterParameter::ARRAY: 215 bindProgramArrayParameters(uniformLocation, static_cast<CustomFilterArrayParameter*>(parameter)); 216 break; 217 case CustomFilterParameter::NUMBER: 218 bindProgramNumberParameters(uniformLocation, static_cast<CustomFilterNumberParameter*>(parameter)); 219 break; 220 case CustomFilterParameter::TRANSFORM: 221 bindProgramTransformParameter(uniformLocation, static_cast<CustomFilterTransformParameter*>(parameter)); 222 break; 223 } 224 } 225 } 226 227 void CustomFilterRenderer::bindProgramAndBuffers(Platform3DObject inputTexture) 228 { 229 ASSERT(m_compiledProgram->isInitialized()); 230 231 m_context->useProgram(m_compiledProgram->program()); 232 233 if (programNeedsInputTexture()) { 234 // We should be binding the DOM element texture sampler only if the author is using the CSS mix function. 235 ASSERT(m_programType == PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE); 236 ASSERT(m_compiledProgram->samplerLocation() != -1); 237 238 m_context->activeTexture(GraphicsContext3D::TEXTURE0); 239 m_context->uniform1i(m_compiledProgram->samplerLocation(), 0); 240 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, inputTexture); 241 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); 242 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); 243 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); 244 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); 245 } 246 247 if (m_compiledProgram->projectionMatrixLocation() != -1) { 248 TransformationMatrix projectionMatrix; 249 orthogonalProjectionMatrix(projectionMatrix, -0.5, 0.5, -0.5, 0.5); 250 float glProjectionMatrix[16]; 251 projectionMatrix.toColumnMajorFloatArray(glProjectionMatrix); 252 m_context->uniformMatrix4fv(m_compiledProgram->projectionMatrixLocation(), 1, false, &glProjectionMatrix[0]); 253 } 254 255 ASSERT(m_meshColumns); 256 ASSERT(m_meshRows); 257 258 if (m_compiledProgram->meshSizeLocation() != -1) 259 m_context->uniform2f(m_compiledProgram->meshSizeLocation(), m_meshColumns, m_meshRows); 260 261 if (m_compiledProgram->tileSizeLocation() != -1) 262 m_context->uniform2f(m_compiledProgram->tileSizeLocation(), 1.0 / m_meshColumns, 1.0 / m_meshRows); 263 264 if (m_compiledProgram->meshBoxLocation() != -1) { 265 // FIXME: This will change when filter margins will be implemented, 266 // see https://bugs.webkit.org/show_bug.cgi?id=71400 267 m_context->uniform4f(m_compiledProgram->meshBoxLocation(), -0.5, -0.5, 1.0, 1.0); 268 } 269 270 if (m_compiledProgram->samplerSizeLocation() != -1) 271 m_context->uniform2f(m_compiledProgram->samplerSizeLocation(), m_contextSize.width(), m_contextSize.height()); 272 273 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_mesh->verticesBufferObject()); 274 m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_mesh->elementsBufferObject()); 275 276 bindVertexAttribute(m_compiledProgram->positionAttribLocation(), PositionAttribSize, PositionAttribOffset); 277 bindVertexAttribute(m_compiledProgram->texAttribLocation(), TexAttribSize, TexAttribOffset); 278 bindVertexAttribute(m_compiledProgram->meshAttribLocation(), MeshAttribSize, MeshAttribOffset); 279 if (m_meshType == MeshTypeDetached) 280 bindVertexAttribute(m_compiledProgram->triangleAttribLocation(), TriangleAttribSize, TriangleAttribOffset); 281 282 bindProgramParameters(); 283 } 284 285 void CustomFilterRenderer::unbindVertexAttributes() 286 { 287 unbindVertexAttribute(m_compiledProgram->positionAttribLocation()); 288 unbindVertexAttribute(m_compiledProgram->texAttribLocation()); 289 unbindVertexAttribute(m_compiledProgram->meshAttribLocation()); 290 if (m_meshType == MeshTypeDetached) 291 unbindVertexAttribute(m_compiledProgram->triangleAttribLocation()); 292 } 293 294 } // namespace WebCore 295