1 /* 2 * Copyright (c) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #if ENABLE(ACCELERATED_2D_CANVAS) 34 35 #include "SharedGraphicsContext3D.h" 36 37 #include "AffineTransform.h" 38 #include "BicubicShader.h" 39 #include "Color.h" 40 #include "ConvolutionShader.h" 41 #include "DrawingBuffer.h" 42 #include "Extensions3D.h" 43 #include "FloatRect.h" 44 #include "IntSize.h" 45 #include "LoopBlinnSolidFillShader.h" 46 #include "SolidFillShader.h" 47 #include "TexShader.h" 48 49 #if ENABLE(SKIA_GPU) 50 #include "GrContext.h" 51 // Limit the number of textures we hold in the bitmap->texture cache. 52 static const int maxTextureCacheCount = 512; 53 // Limit the bytes allocated toward textures in the bitmap->texture cache. 54 static const size_t maxTextureCacheBytes = 50 * 1024 * 1024; 55 #endif 56 57 #include <wtf/OwnArrayPtr.h> 58 #include <wtf/text/CString.h> 59 #include <wtf/text/WTFString.h> 60 61 namespace WebCore { 62 63 // static 64 PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(HostWindow* hostWindow) 65 { 66 GraphicsContext3D::Attributes attr; 67 attr.depth = false; 68 attr.stencil = true; 69 attr.antialias = useLoopBlinnForPathRendering(); 70 attr.canRecoverFromContextLoss = false; // Canvas contexts can not handle lost contexts. 71 RefPtr<GraphicsContext3D> context = GraphicsContext3D::create(attr, hostWindow); 72 if (!context) 73 return 0; 74 OwnPtr<SolidFillShader> solidFillShader = SolidFillShader::create(context.get()); 75 if (!solidFillShader) 76 return 0; 77 OwnPtr<TexShader> texShader = TexShader::create(context.get()); 78 if (!texShader) 79 return 0; 80 OwnPtr<BicubicShader> bicubicShader = BicubicShader::create(context.get()); 81 if (!bicubicShader) 82 return 0; 83 OwnArrayPtr<OwnPtr<ConvolutionShader> > convolutionShaders = adoptArrayPtr(new OwnPtr<ConvolutionShader>[cMaxKernelWidth]); 84 for (int i = 0; i < cMaxKernelWidth; ++i) { 85 convolutionShaders[i] = ConvolutionShader::create(context.get(), i + 1); 86 if (!convolutionShaders[i]) 87 return 0; 88 } 89 return adoptRef(new SharedGraphicsContext3D(context.release(), solidFillShader.release(), texShader.release(), bicubicShader.release(), convolutionShaders.release())); 90 } 91 92 SharedGraphicsContext3D::SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SolidFillShader> solidFillShader, PassOwnPtr<TexShader> texShader, PassOwnPtr<BicubicShader> bicubicShader, PassOwnArrayPtr<OwnPtr<ConvolutionShader> > convolutionShaders) 93 : m_context(context) 94 , m_bgraSupported(false) 95 , m_quadVertices(0) 96 , m_solidFillShader(solidFillShader) 97 , m_texShader(texShader) 98 , m_bicubicShader(bicubicShader) 99 , m_convolutionShaders(convolutionShaders) 100 , m_oesStandardDerivativesSupported(false) 101 #if ENABLE(SKIA_GPU) 102 , m_grContext(0) 103 #endif 104 { 105 allContexts()->add(this); 106 Extensions3D* extensions = m_context->getExtensions(); 107 m_bgraSupported = extensions->supports("GL_EXT_texture_format_BGRA8888") && extensions->supports("GL_EXT_read_format_bgra"); 108 if (m_bgraSupported) { 109 extensions->ensureEnabled("GL_EXT_texture_format_BGRA8888"); 110 extensions->ensureEnabled("GL_EXT_read_format_bgra"); 111 } 112 m_oesStandardDerivativesSupported = extensions->supports("GL_OES_standard_derivatives"); 113 if (m_oesStandardDerivativesSupported) 114 extensions->ensureEnabled("GL_OES_standard_derivatives"); 115 } 116 117 SharedGraphicsContext3D::~SharedGraphicsContext3D() 118 { 119 m_context->deleteBuffer(m_quadVertices); 120 allContexts()->remove(this); 121 #if ENABLE(SKIA_GPU) 122 GrSafeUnref(m_grContext); 123 #endif 124 } 125 126 void SharedGraphicsContext3D::makeContextCurrent() 127 { 128 m_context->makeContextCurrent(); 129 } 130 131 void SharedGraphicsContext3D::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) 132 { 133 m_context->scissor(x, y, width, height); 134 } 135 136 void SharedGraphicsContext3D::enable(GC3Denum capacity) 137 { 138 m_context->enable(capacity); 139 } 140 141 void SharedGraphicsContext3D::disable(GC3Denum capacity) 142 { 143 m_context->disable(capacity); 144 } 145 146 void SharedGraphicsContext3D::clearColor(const Color& color) 147 { 148 float rgba[4]; 149 color.getRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); 150 m_context->clearColor(rgba[0], rgba[1], rgba[2], rgba[3]); 151 } 152 153 void SharedGraphicsContext3D::clear(GC3Dbitfield mask) 154 { 155 m_context->clear(mask); 156 } 157 158 void SharedGraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count) 159 { 160 m_context->drawArrays(mode, first, count); 161 } 162 163 GC3Denum SharedGraphicsContext3D::getError() 164 { 165 return m_context->getError(); 166 } 167 168 void SharedGraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) 169 { 170 m_context->getIntegerv(pname, value); 171 } 172 173 void SharedGraphicsContext3D::flush() 174 { 175 m_context->flush(); 176 } 177 178 Platform3DObject SharedGraphicsContext3D::createBuffer() 179 { 180 return m_context->createBuffer(); 181 } 182 183 Platform3DObject SharedGraphicsContext3D::createFramebuffer() 184 { 185 return m_context->createFramebuffer(); 186 } 187 188 Platform3DObject SharedGraphicsContext3D::createTexture() 189 { 190 return m_context->createTexture(); 191 } 192 193 void SharedGraphicsContext3D::deleteFramebuffer(Platform3DObject framebuffer) 194 { 195 m_context->deleteFramebuffer(framebuffer); 196 } 197 198 void SharedGraphicsContext3D::deleteTexture(Platform3DObject texture) 199 { 200 m_context->deleteTexture(texture); 201 } 202 203 void SharedGraphicsContext3D::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject texture, GC3Dint level) 204 { 205 m_context->framebufferTexture2D(target, attachment, textarget, texture, level); 206 } 207 208 void SharedGraphicsContext3D::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param) 209 { 210 m_context->texParameteri(target, pname, param); 211 } 212 213 bool SharedGraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels) 214 { 215 if (!pixels) 216 return m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border, format, type); 217 return m_context->texImage2D(target, level, internalformat, width, height, border, format, type, pixels); 218 } 219 220 void SharedGraphicsContext3D::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels) 221 { 222 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); 223 } 224 225 void SharedGraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data) 226 { 227 m_context->readPixels(x, y, width, height, format, type, data); 228 } 229 230 bool SharedGraphicsContext3D::supportsBGRA() 231 { 232 return m_bgraSupported; 233 } 234 235 Texture* SharedGraphicsContext3D::createTexture(NativeImagePtr ptr, Texture::Format format, int width, int height) 236 { 237 RefPtr<Texture> texture = m_textures.get(ptr); 238 if (texture) 239 return texture.get(); 240 241 texture = Texture::create(m_context.get(), format, width, height); 242 Texture* t = texture.get(); 243 m_textures.set(ptr, texture); 244 return t; 245 } 246 247 Texture* SharedGraphicsContext3D::getTexture(NativeImagePtr ptr) 248 { 249 RefPtr<Texture> texture = m_textures.get(ptr); 250 return texture ? texture.get() : 0; 251 } 252 253 void SharedGraphicsContext3D::removeTextureFor(NativeImagePtr ptr) 254 { 255 TextureHashMap::iterator it = m_textures.find(ptr); 256 if (it != m_textures.end()) 257 m_textures.remove(it); 258 } 259 260 // static 261 void SharedGraphicsContext3D::removeTexturesFor(NativeImagePtr ptr) 262 { 263 for (HashSet<SharedGraphicsContext3D*>::iterator it = allContexts()->begin(); it != allContexts()->end(); ++it) 264 (*it)->removeTextureFor(ptr); 265 } 266 267 // static 268 HashSet<SharedGraphicsContext3D*>* SharedGraphicsContext3D::allContexts() 269 { 270 DEFINE_STATIC_LOCAL(HashSet<SharedGraphicsContext3D*>, allContextsSet, ()); 271 return &allContextsSet; 272 } 273 274 275 PassRefPtr<Texture> SharedGraphicsContext3D::createTexture(Texture::Format format, int width, int height) 276 { 277 return Texture::create(m_context.get(), format, width, height); 278 } 279 280 void SharedGraphicsContext3D::applyCompositeOperator(CompositeOperator op) 281 { 282 switch (op) { 283 case CompositeClear: 284 m_context->enable(GraphicsContext3D::BLEND); 285 m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::ZERO); 286 break; 287 case CompositeCopy: 288 m_context->disable(GraphicsContext3D::BLEND); 289 break; 290 case CompositeSourceOver: 291 m_context->enable(GraphicsContext3D::BLEND); 292 m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); 293 break; 294 case CompositeSourceIn: 295 m_context->enable(GraphicsContext3D::BLEND); 296 m_context->blendFunc(GraphicsContext3D::DST_ALPHA, GraphicsContext3D::ZERO); 297 break; 298 case CompositeSourceOut: 299 m_context->enable(GraphicsContext3D::BLEND); 300 m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ZERO); 301 break; 302 case CompositeSourceAtop: 303 m_context->enable(GraphicsContext3D::BLEND); 304 m_context->blendFunc(GraphicsContext3D::DST_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); 305 break; 306 case CompositeDestinationOver: 307 m_context->enable(GraphicsContext3D::BLEND); 308 m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ONE); 309 break; 310 case CompositeDestinationIn: 311 m_context->enable(GraphicsContext3D::BLEND); 312 m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::SRC_ALPHA); 313 break; 314 case CompositeDestinationOut: 315 m_context->enable(GraphicsContext3D::BLEND); 316 m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); 317 break; 318 case CompositeDestinationAtop: 319 m_context->enable(GraphicsContext3D::BLEND); 320 m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::SRC_ALPHA); 321 break; 322 case CompositeXOR: 323 m_context->enable(GraphicsContext3D::BLEND); 324 m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); 325 break; 326 case CompositePlusDarker: 327 case CompositeHighlight: 328 // unsupported 329 m_context->disable(GraphicsContext3D::BLEND); 330 break; 331 case CompositePlusLighter: 332 m_context->enable(GraphicsContext3D::BLEND); 333 m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE); 334 break; 335 } 336 } 337 338 void SharedGraphicsContext3D::enableStencil(bool enable) 339 { 340 if (enable) 341 m_context->enable(GraphicsContext3D::STENCIL_TEST); 342 else 343 m_context->disable(GraphicsContext3D::STENCIL_TEST); 344 } 345 346 void SharedGraphicsContext3D::useQuadVertices() 347 { 348 if (!m_quadVertices) { 349 float vertices[] = { 0.0f, 0.0f, 350 1.0f, 0.0f, 351 0.0f, 1.0f, 352 1.0f, 1.0f }; 353 m_quadVertices = m_context->createBuffer(); 354 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices); 355 m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(vertices), vertices, GraphicsContext3D::STATIC_DRAW); 356 } else { 357 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices); 358 } 359 } 360 361 void SharedGraphicsContext3D::setActiveTexture(GC3Denum textureUnit) 362 { 363 m_context->activeTexture(textureUnit); 364 } 365 366 void SharedGraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer) 367 { 368 m_context->bindBuffer(target, buffer); 369 } 370 371 void SharedGraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture) 372 { 373 m_context->bindTexture(target, texture); 374 } 375 376 void SharedGraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage) 377 { 378 m_context->bufferData(target, size, usage); 379 } 380 381 void SharedGraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage) 382 { 383 m_context->bufferData(target, size, data, usage); 384 } 385 386 void SharedGraphicsContext3D::bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data) 387 { 388 m_context->bufferSubData(target, offset, size, data); 389 } 390 391 void SharedGraphicsContext3D::useFillSolidProgram(const AffineTransform& transform, const Color& color) 392 { 393 m_solidFillShader->use(transform, color); 394 } 395 396 void SharedGraphicsContext3D::useTextureProgram(const AffineTransform& transform, const AffineTransform& texTransform, float alpha) 397 { 398 m_texShader->use(transform, texTransform, 0, alpha); 399 } 400 401 void SharedGraphicsContext3D::useBicubicProgram(const AffineTransform& transform, const AffineTransform& texTransform, const float coefficients[16], const float imageIncrement[2], float alpha) 402 { 403 m_bicubicShader->use(transform, texTransform, coefficients, imageIncrement, alpha); 404 } 405 406 void SharedGraphicsContext3D::useConvolutionProgram(const AffineTransform& transform, const AffineTransform& texTransform, const float* kernel, int kernelWidth, float imageIncrement[2]) 407 { 408 ASSERT(kernelWidth >= 1 && kernelWidth <= cMaxKernelWidth); 409 m_convolutionShaders[kernelWidth - 1]->use(transform, texTransform, kernel, kernelWidth, imageIncrement); 410 } 411 412 void SharedGraphicsContext3D::bindFramebuffer(Platform3DObject framebuffer) 413 { 414 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, framebuffer); 415 } 416 417 void SharedGraphicsContext3D::setViewport(const IntSize& size) 418 { 419 m_context->viewport(0, 0, size.width(), size.height()); 420 } 421 422 bool SharedGraphicsContext3D::paintsIntoCanvasBuffer() const 423 { 424 return m_context->paintsIntoCanvasBuffer(); 425 } 426 427 bool SharedGraphicsContext3D::useLoopBlinnForPathRendering() 428 { 429 return false; 430 } 431 432 void SharedGraphicsContext3D::useLoopBlinnInteriorProgram(unsigned vertexOffset, const AffineTransform& transform, const Color& color) 433 { 434 if (!m_loopBlinnInteriorShader) { 435 m_loopBlinnInteriorShader = LoopBlinnSolidFillShader::create(m_context.get(), 436 LoopBlinnShader::Interior, 437 Shader::NotAntialiased); 438 } 439 ASSERT(m_loopBlinnInteriorShader); 440 m_loopBlinnInteriorShader->use(vertexOffset, 0, transform, color); 441 } 442 443 void SharedGraphicsContext3D::useLoopBlinnExteriorProgram(unsigned vertexOffset, unsigned klmOffset, const AffineTransform& transform, const Color& color) 444 { 445 if (!m_loopBlinnExteriorShader) { 446 m_loopBlinnExteriorShader = LoopBlinnSolidFillShader::create(m_context.get(), 447 LoopBlinnShader::Exterior, 448 m_oesStandardDerivativesSupported ? Shader::Antialiased : Shader::NotAntialiased); 449 } 450 ASSERT(m_loopBlinnExteriorShader); 451 m_loopBlinnExteriorShader->use(vertexOffset, klmOffset, transform, color); 452 } 453 454 DrawingBuffer* SharedGraphicsContext3D::getOffscreenBuffer(unsigned index, const IntSize& size) 455 { 456 if (index >= m_offscreenBuffers.size()) 457 m_offscreenBuffers.resize(index + 1); 458 459 if (!m_offscreenBuffers[index]) 460 m_offscreenBuffers[index] = m_context->createDrawingBuffer(size); 461 462 if (size.width() != m_offscreenBuffers[index]->size().width() 463 || size.height() != m_offscreenBuffers[index]->size().height()) 464 m_offscreenBuffers[index]->reset(size); 465 return m_offscreenBuffers[index].get(); 466 } 467 468 #if ENABLE(SKIA_GPU) 469 GrContext* SharedGraphicsContext3D::grContext() 470 { 471 if (!m_grContext) { 472 m_grContext = GrContext::CreateGLShaderContext(); 473 m_grContext->setTextureCacheLimits(maxTextureCacheCount, maxTextureCacheBytes); 474 } 475 return m_grContext; 476 } 477 #endif 478 479 } // namespace WebCore 480 481 #endif 482