bool FECustomFilter::applyShader() { Uint8ClampedArray* dstPixelArray = createUnmultipliedImageResult(); if (!dstPixelArray) return false; if (!prepareForDrawing()) return false; FilterEffect* in = inputEffect(0); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); IntSize newContextSize(effectDrawingRect.size()); if (!resizeContextIfNeeded(newContextSize)) return false; bool needsInputTexture = programNeedsInputTexture(); if (needsInputTexture) { RefPtr<Uint8ClampedArray> srcPixelArray = in->asUnmultipliedImage(effectDrawingRect); uploadInputTexture(srcPixelArray.get()); } drawFilterMesh(needsInputTexture ? m_inputTexture : 0); ASSERT(static_cast<size_t>(newContextSize.width() * newContextSize.height() * 4) == dstPixelArray->length()); m_context->readPixels(0, 0, newContextSize.width(), newContextSize.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, dstPixelArray->data()); return true; }
void CustomFilterRenderer::bindProgramAndBuffers(Platform3DObject inputTexture) { ASSERT(m_compiledProgram->isInitialized()); m_context->useProgram(m_compiledProgram->program()); if (programNeedsInputTexture()) { // We should be binding the DOM element texture sampler only if the author is using the CSS mix function. ASSERT(m_programType == PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE); ASSERT(m_compiledProgram->samplerLocation() != -1); m_context->activeTexture(GraphicsContext3D::TEXTURE0); m_context->uniform1i(m_compiledProgram->samplerLocation(), 0); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, inputTexture); m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); } if (m_compiledProgram->projectionMatrixLocation() != -1) { TransformationMatrix projectionMatrix; orthogonalProjectionMatrix(projectionMatrix, -0.5, 0.5, -0.5, 0.5); float glProjectionMatrix[16]; projectionMatrix.toColumnMajorFloatArray(glProjectionMatrix); m_context->uniformMatrix4fv(m_compiledProgram->projectionMatrixLocation(), 1, false, &glProjectionMatrix[0]); } ASSERT(m_meshColumns); ASSERT(m_meshRows); if (m_compiledProgram->meshSizeLocation() != -1) m_context->uniform2f(m_compiledProgram->meshSizeLocation(), m_meshColumns, m_meshRows); if (m_compiledProgram->tileSizeLocation() != -1) m_context->uniform2f(m_compiledProgram->tileSizeLocation(), 1.0 / m_meshColumns, 1.0 / m_meshRows); if (m_compiledProgram->meshBoxLocation() != -1) { // FIXME: This will change when filter margins will be implemented, // see https://bugs.webkit.org/show_bug.cgi?id=71400 m_context->uniform4f(m_compiledProgram->meshBoxLocation(), -0.5, -0.5, 1.0, 1.0); } if (m_compiledProgram->samplerSizeLocation() != -1) m_context->uniform2f(m_compiledProgram->samplerSizeLocation(), m_contextSize.width(), m_contextSize.height()); m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_mesh->verticesBufferObject()); m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_mesh->elementsBufferObject()); bindVertexAttribute(m_compiledProgram->positionAttribLocation(), PositionAttribSize, PositionAttribOffset); bindVertexAttribute(m_compiledProgram->texAttribLocation(), TexAttribSize, TexAttribOffset); bindVertexAttribute(m_compiledProgram->meshAttribLocation(), MeshAttribSize, MeshAttribOffset); if (m_meshType == MeshTypeDetached) bindVertexAttribute(m_compiledProgram->triangleAttribLocation(), TriangleAttribSize, TriangleAttribOffset); bindProgramParameters(); }
bool FECustomFilter::prepareForDrawing(CustomFilterDrawType filterDrawType) { if (!m_context && !initializeContext()) return false; m_context->makeContextCurrent(); // If the shader had compiler errors we cannot draw anything. if (!m_compiledProgram->isInitialized()) return false; // Only allocate a texture if the program needs one and the caller doesn't allocate one by itself. if ((programNeedsInputTexture() && (filterDrawType == NEEDS_INPUT_TEXTURE) && !ensureInputTexture()) || !ensureFrameBuffer()) return false; return true; }
void FECustomFilter::bindProgramAndBuffers(Platform3DObject inputTexture) { ASSERT(m_compiledProgram->isInitialized()); m_context->useProgram(m_compiledProgram->program()); if (programNeedsInputTexture()) { // We should be binding the DOM element texture sampler only if the author is using the CSS mix function. ASSERT(m_validatedProgram->programInfo().programType() == PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE); ASSERT(m_compiledProgram->samplerLocation() != -1); m_context->activeTexture(GraphicsContext3D::TEXTURE0); m_context->uniform1i(m_compiledProgram->samplerLocation(), 0); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, inputTexture); m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); } if (m_compiledProgram->projectionMatrixLocation() != -1) { TransformationMatrix projectionMatrix; orthogonalProjectionMatrix(projectionMatrix, -0.5, 0.5, -0.5, 0.5); float glProjectionMatrix[16]; projectionMatrix.toColumnMajorFloatArray(glProjectionMatrix); m_context->uniformMatrix4fv(m_compiledProgram->projectionMatrixLocation(), 1, false, &glProjectionMatrix[0]); } ASSERT(m_meshColumns); ASSERT(m_meshRows); if (m_compiledProgram->meshSizeLocation() != -1) m_context->uniform2f(m_compiledProgram->meshSizeLocation(), m_meshColumns, m_meshRows); if (m_compiledProgram->tileSizeLocation() != -1) m_context->uniform2f(m_compiledProgram->tileSizeLocation(), 1.0 / m_meshColumns, 1.0 / m_meshRows); if (m_compiledProgram->meshBoxLocation() != -1) { // FIXME: This will change when filter margins will be implemented, // see https://bugs.webkit.org/show_bug.cgi?id=71400 m_context->uniform4f(m_compiledProgram->meshBoxLocation(), -0.5, -0.5, 1.0, 1.0); } if (m_compiledProgram->samplerSizeLocation() != -1) m_context->uniform2f(m_compiledProgram->samplerSizeLocation(), m_contextSize.width(), m_contextSize.height()); m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_mesh->verticesBufferObject()); m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_mesh->elementsBufferObject()); // FIXME: Ideally, these should be public members of CustomFilterMesh. // https://bugs.webkit.org/show_bug.cgi?id=94755 static const unsigned PositionAttribSize = 4; static const unsigned TexAttribSize = 2; static const unsigned MeshAttribSize = 2; static const unsigned TriangleAttribSize = 3; static const unsigned PositionAttribOffset = 0; static const unsigned TexAttribOffset = PositionAttribOffset + PositionAttribSize * sizeof(float); static const unsigned MeshAttribOffset = TexAttribOffset + TexAttribSize * sizeof(float); static const unsigned TriangleAttribOffset = MeshAttribOffset + MeshAttribSize * sizeof(float); bindVertexAttribute(m_compiledProgram->positionAttribLocation(), PositionAttribSize, PositionAttribOffset); bindVertexAttribute(m_compiledProgram->texAttribLocation(), TexAttribSize, TexAttribOffset); // FIXME: Get rid of the internal tex coord attribute "css_a_texCoord". // https://bugs.webkit.org/show_bug.cgi?id=94358 bindVertexAttribute(m_compiledProgram->internalTexCoordAttribLocation(), TexAttribSize, TexAttribOffset); bindVertexAttribute(m_compiledProgram->meshAttribLocation(), MeshAttribSize, MeshAttribOffset); if (m_meshType == CustomFilterOperation::DETACHED) bindVertexAttribute(m_compiledProgram->triangleAttribLocation(), TriangleAttribSize, TriangleAttribOffset); bindProgramParameters(); }