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
create(HostWindow * hostWindow)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
SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D> context,PassOwnPtr<SolidFillShader> solidFillShader,PassOwnPtr<TexShader> texShader,PassOwnPtr<BicubicShader> bicubicShader,PassOwnArrayPtr<OwnPtr<ConvolutionShader>> convolutionShaders)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
~SharedGraphicsContext3D()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
makeContextCurrent()126 void SharedGraphicsContext3D::makeContextCurrent()
127 {
128 m_context->makeContextCurrent();
129 }
130
scissor(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height)131 void SharedGraphicsContext3D::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
132 {
133 m_context->scissor(x, y, width, height);
134 }
135
enable(GC3Denum capacity)136 void SharedGraphicsContext3D::enable(GC3Denum capacity)
137 {
138 m_context->enable(capacity);
139 }
140
disable(GC3Denum capacity)141 void SharedGraphicsContext3D::disable(GC3Denum capacity)
142 {
143 m_context->disable(capacity);
144 }
145
clearColor(const Color & color)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
clear(GC3Dbitfield mask)153 void SharedGraphicsContext3D::clear(GC3Dbitfield mask)
154 {
155 m_context->clear(mask);
156 }
157
drawArrays(GC3Denum mode,GC3Dint first,GC3Dsizei count)158 void SharedGraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count)
159 {
160 m_context->drawArrays(mode, first, count);
161 }
162
getError()163 GC3Denum SharedGraphicsContext3D::getError()
164 {
165 return m_context->getError();
166 }
167
getIntegerv(GC3Denum pname,GC3Dint * value)168 void SharedGraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value)
169 {
170 m_context->getIntegerv(pname, value);
171 }
172
flush()173 void SharedGraphicsContext3D::flush()
174 {
175 m_context->flush();
176 }
177
createBuffer()178 Platform3DObject SharedGraphicsContext3D::createBuffer()
179 {
180 return m_context->createBuffer();
181 }
182
createFramebuffer()183 Platform3DObject SharedGraphicsContext3D::createFramebuffer()
184 {
185 return m_context->createFramebuffer();
186 }
187
createTexture()188 Platform3DObject SharedGraphicsContext3D::createTexture()
189 {
190 return m_context->createTexture();
191 }
192
deleteFramebuffer(Platform3DObject framebuffer)193 void SharedGraphicsContext3D::deleteFramebuffer(Platform3DObject framebuffer)
194 {
195 m_context->deleteFramebuffer(framebuffer);
196 }
197
deleteTexture(Platform3DObject texture)198 void SharedGraphicsContext3D::deleteTexture(Platform3DObject texture)
199 {
200 m_context->deleteTexture(texture);
201 }
202
framebufferTexture2D(GC3Denum target,GC3Denum attachment,GC3Denum textarget,Platform3DObject texture,GC3Dint level)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
texParameteri(GC3Denum target,GC3Denum pname,GC3Dint param)208 void SharedGraphicsContext3D::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
209 {
210 m_context->texParameteri(target, pname, param);
211 }
212
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height,GC3Dint border,GC3Denum format,GC3Denum type,const void * pixels)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
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,const void * pixels)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
readPixels(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,void * data)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
supportsBGRA()230 bool SharedGraphicsContext3D::supportsBGRA()
231 {
232 return m_bgraSupported;
233 }
234
createTexture(NativeImagePtr ptr,Texture::Format format,int width,int height)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
getTexture(NativeImagePtr ptr)247 Texture* SharedGraphicsContext3D::getTexture(NativeImagePtr ptr)
248 {
249 RefPtr<Texture> texture = m_textures.get(ptr);
250 return texture ? texture.get() : 0;
251 }
252
removeTextureFor(NativeImagePtr ptr)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
removeTexturesFor(NativeImagePtr ptr)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
allContexts()268 HashSet<SharedGraphicsContext3D*>* SharedGraphicsContext3D::allContexts()
269 {
270 DEFINE_STATIC_LOCAL(HashSet<SharedGraphicsContext3D*>, allContextsSet, ());
271 return &allContextsSet;
272 }
273
274
createTexture(Texture::Format format,int width,int height)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
applyCompositeOperator(CompositeOperator op)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
enableStencil(bool enable)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
useQuadVertices()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
setActiveTexture(GC3Denum textureUnit)361 void SharedGraphicsContext3D::setActiveTexture(GC3Denum textureUnit)
362 {
363 m_context->activeTexture(textureUnit);
364 }
365
bindBuffer(GC3Denum target,Platform3DObject buffer)366 void SharedGraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer)
367 {
368 m_context->bindBuffer(target, buffer);
369 }
370
bindTexture(GC3Denum target,Platform3DObject texture)371 void SharedGraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture)
372 {
373 m_context->bindTexture(target, texture);
374 }
375
bufferData(GC3Denum target,GC3Dsizeiptr size,GC3Denum usage)376 void SharedGraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage)
377 {
378 m_context->bufferData(target, size, usage);
379 }
380
bufferData(GC3Denum target,GC3Dsizeiptr size,const void * data,GC3Denum usage)381 void SharedGraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage)
382 {
383 m_context->bufferData(target, size, data, usage);
384 }
385
bufferSubData(GC3Denum target,GC3Dintptr offset,GC3Dsizeiptr size,const void * data)386 void SharedGraphicsContext3D::bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data)
387 {
388 m_context->bufferSubData(target, offset, size, data);
389 }
390
useFillSolidProgram(const AffineTransform & transform,const Color & color)391 void SharedGraphicsContext3D::useFillSolidProgram(const AffineTransform& transform, const Color& color)
392 {
393 m_solidFillShader->use(transform, color);
394 }
395
useTextureProgram(const AffineTransform & transform,const AffineTransform & texTransform,float alpha)396 void SharedGraphicsContext3D::useTextureProgram(const AffineTransform& transform, const AffineTransform& texTransform, float alpha)
397 {
398 m_texShader->use(transform, texTransform, 0, alpha);
399 }
400
useBicubicProgram(const AffineTransform & transform,const AffineTransform & texTransform,const float coefficients[16],const float imageIncrement[2],float alpha)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
useConvolutionProgram(const AffineTransform & transform,const AffineTransform & texTransform,const float * kernel,int kernelWidth,float imageIncrement[2])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
bindFramebuffer(Platform3DObject framebuffer)412 void SharedGraphicsContext3D::bindFramebuffer(Platform3DObject framebuffer)
413 {
414 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, framebuffer);
415 }
416
setViewport(const IntSize & size)417 void SharedGraphicsContext3D::setViewport(const IntSize& size)
418 {
419 m_context->viewport(0, 0, size.width(), size.height());
420 }
421
paintsIntoCanvasBuffer() const422 bool SharedGraphicsContext3D::paintsIntoCanvasBuffer() const
423 {
424 return m_context->paintsIntoCanvasBuffer();
425 }
426
useLoopBlinnForPathRendering()427 bool SharedGraphicsContext3D::useLoopBlinnForPathRendering()
428 {
429 return false;
430 }
431
useLoopBlinnInteriorProgram(unsigned vertexOffset,const AffineTransform & transform,const Color & color)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
useLoopBlinnExteriorProgram(unsigned vertexOffset,unsigned klmOffset,const AffineTransform & transform,const Color & color)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
getOffscreenBuffer(unsigned index,const IntSize & size)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)
grContext()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