OLD | NEW |
| (Empty) |
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 #include "core/platform/graphics/gpu/DrawingBuffer.h" | |
34 | |
35 #include <algorithm> | |
36 #include "core/platform/graphics/Extensions3D.h" | |
37 #include "core/platform/graphics/GraphicsLayer.h" | |
38 #include "platform/TraceEvent.h" | |
39 #include "public/platform/Platform.h" | |
40 #include "public/platform/WebCompositorSupport.h" | |
41 #include "public/platform/WebExternalBitmap.h" | |
42 #include "public/platform/WebExternalTextureLayer.h" | |
43 #include "public/platform/WebGraphicsContext3D.h" | |
44 | |
45 using namespace std; | |
46 | |
47 namespace WebCore { | |
48 | |
49 // Global resource ceiling (expressed in terms of pixels) for DrawingBuffer crea
tion and resize. | |
50 // When this limit is set, DrawingBuffer::create() and DrawingBuffer::reset() ca
lls that would | |
51 // exceed the global cap will instead clear the buffer. | |
52 static const int s_maximumResourceUsePixels = 16 * 1024 * 1024; | |
53 static int s_currentResourceUsePixels = 0; | |
54 static const float s_resourceAdjustedRatio = 0.5; | |
55 | |
56 static const bool s_allowContextEvictionOnCreate = true; | |
57 static const int s_maxScaleAttempts = 3; | |
58 | |
59 class ScopedTextureUnit0BindingRestorer { | |
60 public: | |
61 ScopedTextureUnit0BindingRestorer(GraphicsContext3D* context, GC3Denum activ
eTextureUnit, Platform3DObject textureUnitZeroId) | |
62 : m_context(context) | |
63 , m_oldActiveTextureUnit(activeTextureUnit) | |
64 , m_oldTextureUnitZeroId(textureUnitZeroId) | |
65 { | |
66 m_context->activeTexture(GraphicsContext3D::TEXTURE0); | |
67 } | |
68 ~ScopedTextureUnit0BindingRestorer() | |
69 { | |
70 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_oldTextureUnitZe
roId); | |
71 m_context->activeTexture(m_oldActiveTextureUnit); | |
72 } | |
73 | |
74 private: | |
75 GraphicsContext3D* m_context; | |
76 GC3Denum m_oldActiveTextureUnit; | |
77 Platform3DObject m_oldTextureUnitZeroId; | |
78 }; | |
79 | |
80 PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, cons
t IntSize& size, PreserveDrawingBuffer preserve, PassRefPtr<ContextEvictionManag
er> contextEvictionManager) | |
81 { | |
82 Extensions3D* extensions = context->extensions(); | |
83 bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit"
) | |
84 && extensions->supports("GL_ANGLE_framebuffer_multisample") | |
85 && extensions->supports("GL_OES_rgb8_rgba8"); | |
86 if (multisampleSupported) { | |
87 extensions->ensureEnabled("GL_ANGLE_framebuffer_blit"); | |
88 extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); | |
89 extensions->ensureEnabled("GL_OES_rgb8_rgba8"); | |
90 } | |
91 bool packedDepthStencilSupported = extensions->supports("GL_OES_packed_depth
_stencil"); | |
92 if (packedDepthStencilSupported) | |
93 extensions->ensureEnabled("GL_OES_packed_depth_stencil"); | |
94 | |
95 RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, si
ze, multisampleSupported, packedDepthStencilSupported, preserve, contextEviction
Manager)); | |
96 return drawingBuffer.release(); | |
97 } | |
98 | |
99 DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, | |
100 const IntSize& size, | |
101 bool multisampleExtensionSupported, | |
102 bool packedDepthStencilExtensionSupported, | |
103 PreserveDrawingBuffer preserve, | |
104 PassRefPtr<ContextEvictionManager> contextEvictionM
anager) | |
105 : m_preserveDrawingBuffer(preserve) | |
106 , m_scissorEnabled(false) | |
107 , m_texture2DBinding(0) | |
108 , m_framebufferBinding(0) | |
109 , m_activeTextureUnit(GraphicsContext3D::TEXTURE0) | |
110 , m_context(context) | |
111 , m_size(-1, -1) | |
112 , m_multisampleExtensionSupported(multisampleExtensionSupported) | |
113 , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupporte
d) | |
114 , m_fbo(0) | |
115 , m_colorBuffer(0) | |
116 , m_frontColorBuffer(0) | |
117 , m_depthStencilBuffer(0) | |
118 , m_depthBuffer(0) | |
119 , m_stencilBuffer(0) | |
120 , m_multisampleFBO(0) | |
121 , m_multisampleColorBuffer(0) | |
122 , m_contentsChanged(true) | |
123 , m_contentsChangeCommitted(false) | |
124 , m_internalColorFormat(0) | |
125 , m_colorFormat(0) | |
126 , m_internalRenderbufferFormat(0) | |
127 , m_maxTextureSize(0) | |
128 , m_contextEvictionManager(contextEvictionManager) | |
129 { | |
130 // Used by browser tests to detect the use of a DrawingBuffer. | |
131 TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation"); | |
132 initialize(size); | |
133 } | |
134 | |
135 DrawingBuffer::~DrawingBuffer() | |
136 { | |
137 releaseResources(); | |
138 } | |
139 | |
140 void DrawingBuffer::markContentsChanged() | |
141 { | |
142 m_contentsChanged = true; | |
143 m_contentsChangeCommitted = false; | |
144 } | |
145 | |
146 blink::WebGraphicsContext3D* DrawingBuffer::context() | |
147 { | |
148 if (!m_context) | |
149 return 0; | |
150 return m_context->webContext(); | |
151 } | |
152 | |
153 bool DrawingBuffer::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox,
blink::WebExternalBitmap* bitmap) | |
154 { | |
155 if (!m_context || !m_contentsChanged || !m_lastColorBuffer) | |
156 return false; | |
157 | |
158 m_context->makeContextCurrent(); | |
159 | |
160 // Resolve the multisampled buffer into the texture referenced by m_lastColo
rBuffer mailbox. | |
161 if (multisample()) | |
162 commit(); | |
163 | |
164 if (bitmap) { | |
165 bitmap->setSize(size()); | |
166 | |
167 unsigned char* pixels = bitmap->pixels(); | |
168 bool needPremultiply = m_attributes.alpha && !m_attributes.premultiplied
Alpha; | |
169 GraphicsContext3D::AlphaOp op = needPremultiply ? GraphicsContext3D::Alp
haDoPremultiply : GraphicsContext3D::AlphaDoNothing; | |
170 if (pixels) | |
171 m_context->readBackFramebuffer(pixels, size().width(), size().height
(), GraphicsContext3D::ReadbackSkia, op); | |
172 } | |
173 | |
174 // We must restore the texture binding since creating new textures, | |
175 // consuming and producing mailboxes changes it. | |
176 ScopedTextureUnit0BindingRestorer restorer(m_context.get(), m_activeTextureU
nit, m_texture2DBinding); | |
177 | |
178 // First try to recycle an old buffer. | |
179 RefPtr<MailboxInfo> nextFrontColorBuffer = recycledMailbox(); | |
180 | |
181 // No buffer available to recycle, create a new one. | |
182 if (!nextFrontColorBuffer) { | |
183 unsigned newColorBuffer = createColorTexture(m_size); | |
184 // Bad things happened, abandon ship. | |
185 if (!newColorBuffer) | |
186 return false; | |
187 | |
188 nextFrontColorBuffer = createNewMailbox(newColorBuffer); | |
189 } | |
190 | |
191 if (m_preserveDrawingBuffer == Discard) { | |
192 m_colorBuffer = nextFrontColorBuffer->textureId; | |
193 swap(nextFrontColorBuffer, m_lastColorBuffer); | |
194 // It appears safe to overwrite the context's framebuffer binding in the
Discard case since there will always be a | |
195 // WebGLRenderingContext::clearIfComposited() call made before the next
draw call which restores the framebuffer binding. | |
196 // If this stops being true at some point, we should track the current f
ramebuffer binding in the DrawingBuffer and restore | |
197 // it after attaching the new back buffer here. | |
198 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); | |
199 m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, Graphics
Context3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); | |
200 } else { | |
201 Extensions3D* extensions = m_context->extensions(); | |
202 extensions->copyTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, m_colorBu
ffer, nextFrontColorBuffer->textureId, 0, GraphicsContext3D::RGBA, GraphicsConte
xt3D::UNSIGNED_BYTE); | |
203 } | |
204 | |
205 if (multisample() && !m_framebufferBinding) | |
206 bind(); | |
207 else | |
208 restoreFramebufferBinding(); | |
209 | |
210 m_contentsChanged = false; | |
211 | |
212 context()->bindTexture(GraphicsContext3D::TEXTURE_2D, nextFrontColorBuffer->
textureId); | |
213 context()->produceTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, nextFrontCo
lorBuffer->mailbox.name); | |
214 context()->flush(); | |
215 m_context->markLayerComposited(); | |
216 | |
217 *outMailbox = nextFrontColorBuffer->mailbox; | |
218 m_frontColorBuffer = nextFrontColorBuffer->textureId; | |
219 return true; | |
220 } | |
221 | |
222 void DrawingBuffer::mailboxReleased(const blink::WebExternalTextureMailbox& mail
box) | |
223 { | |
224 for (size_t i = 0; i < m_textureMailboxes.size(); i++) { | |
225 RefPtr<MailboxInfo> mailboxInfo = m_textureMailboxes[i]; | |
226 if (!memcmp(mailboxInfo->mailbox.name, mailbox.name, sizeof(mailbox.nam
e))) { | |
227 mailboxInfo->mailbox.syncPoint = mailbox.syncPoint; | |
228 m_recycledMailboxes.append(mailboxInfo.release()); | |
229 return; | |
230 } | |
231 } | |
232 ASSERT_NOT_REACHED(); | |
233 } | |
234 | |
235 PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::recycledMailbox() | |
236 { | |
237 if (!m_context || m_recycledMailboxes.isEmpty()) | |
238 return PassRefPtr<MailboxInfo>(); | |
239 | |
240 RefPtr<MailboxInfo> mailboxInfo = m_recycledMailboxes.last().release(); | |
241 m_recycledMailboxes.removeLast(); | |
242 | |
243 if (mailboxInfo->mailbox.syncPoint) { | |
244 context()->waitSyncPoint(mailboxInfo->mailbox.syncPoint); | |
245 mailboxInfo->mailbox.syncPoint = 0; | |
246 } | |
247 | |
248 context()->bindTexture(GraphicsContext3D::TEXTURE_2D, mailboxInfo->textureId
); | |
249 context()->consumeTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, mailboxInfo
->mailbox.name); | |
250 | |
251 if (mailboxInfo->size != m_size) { | |
252 m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, m_in
ternalColorFormat, m_size.width(), m_size.height(), 0, m_colorFormat, GraphicsCo
ntext3D::UNSIGNED_BYTE); | |
253 mailboxInfo->size = m_size; | |
254 } | |
255 | |
256 return mailboxInfo.release(); | |
257 } | |
258 | |
259 PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::createNewMailbox(unsigned
textureId) | |
260 { | |
261 RefPtr<MailboxInfo> returnMailbox = adoptRef(new MailboxInfo()); | |
262 context()->genMailboxCHROMIUM(returnMailbox->mailbox.name); | |
263 returnMailbox->textureId = textureId; | |
264 returnMailbox->size = m_size; | |
265 m_textureMailboxes.append(returnMailbox); | |
266 return returnMailbox.release(); | |
267 } | |
268 | |
269 void DrawingBuffer::initialize(const IntSize& size) | |
270 { | |
271 ASSERT(m_context); | |
272 m_attributes = m_context->getContextAttributes(); | |
273 | |
274 if (m_attributes.alpha) { | |
275 m_internalColorFormat = GraphicsContext3D::RGBA; | |
276 m_colorFormat = GraphicsContext3D::RGBA; | |
277 m_internalRenderbufferFormat = Extensions3D::RGBA8_OES; | |
278 } else { | |
279 m_internalColorFormat = GraphicsContext3D::RGB; | |
280 m_colorFormat = GraphicsContext3D::RGB; | |
281 m_internalRenderbufferFormat = Extensions3D::RGB8_OES; | |
282 } | |
283 | |
284 m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSiz
e); | |
285 | |
286 m_fbo = m_context->createFramebuffer(); | |
287 | |
288 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); | |
289 m_colorBuffer = createColorTexture(); | |
290 m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsCont
ext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); | |
291 createSecondaryBuffers(); | |
292 reset(size); | |
293 m_lastColorBuffer = createNewMailbox(m_colorBuffer); | |
294 } | |
295 | |
296 unsigned DrawingBuffer::frontColorBuffer() const | |
297 { | |
298 return m_frontColorBuffer; | |
299 } | |
300 | |
301 bool DrawingBuffer::copyToPlatformTexture(GraphicsContext3D& context, Platform3D
Object texture, GC3Denum internalFormat, GC3Denum destType, GC3Dint level, bool
premultiplyAlpha, bool flipY) | |
302 { | |
303 if (!m_context || !m_context->makeContextCurrent()) | |
304 return false; | |
305 if (m_contentsChanged) { | |
306 if (multisample()) { | |
307 commit(); | |
308 if (!m_framebufferBinding) | |
309 bind(); | |
310 else | |
311 restoreFramebufferBinding(); | |
312 } | |
313 m_context->flush(); | |
314 } | |
315 Platform3DObject sourceTexture = colorBuffer(); | |
316 | |
317 if (!context.makeContextCurrent()) | |
318 return false; | |
319 Extensions3D* extensions = context.extensions(); | |
320 if (!extensions->supports("GL_CHROMIUM_copy_texture") || !extensions->suppor
ts("GL_CHROMIUM_flipy") | |
321 || !extensions->canUseCopyTextureCHROMIUM(internalFormat, destType, leve
l)) | |
322 return false; | |
323 | |
324 bool unpackPremultiplyAlphaNeeded = false; | |
325 bool unpackUnpremultiplyAlphaNeeded = false; | |
326 if (m_attributes.alpha && m_attributes.premultipliedAlpha && !premultiplyAlp
ha) | |
327 unpackUnpremultiplyAlphaNeeded = true; | |
328 else if (m_attributes.alpha && !m_attributes.premultipliedAlpha && premultip
lyAlpha) | |
329 unpackPremultiplyAlphaNeeded = true; | |
330 | |
331 context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, unpac
kUnpremultiplyAlphaNeeded); | |
332 context.pixelStorei(Extensions3D::UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, unpackP
remultiplyAlphaNeeded); | |
333 context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, flipY); | |
334 extensions->copyTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, sourceTexture
, texture, level, internalFormat, destType); | |
335 context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, false); | |
336 context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false
); | |
337 context.pixelStorei(Extensions3D::UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); | |
338 | |
339 return true; | |
340 } | |
341 | |
342 Platform3DObject DrawingBuffer::framebuffer() const | |
343 { | |
344 return m_fbo; | |
345 } | |
346 | |
347 blink::WebLayer* DrawingBuffer::platformLayer() | |
348 { | |
349 if (!m_context) | |
350 return 0; | |
351 | |
352 if (!m_layer) { | |
353 m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->crea
teExternalTextureLayer(this)); | |
354 | |
355 m_layer->setOpaque(!m_attributes.alpha); | |
356 m_layer->setBlendBackgroundColor(m_attributes.alpha); | |
357 m_layer->setPremultipliedAlpha(m_attributes.premultipliedAlpha); | |
358 GraphicsLayer::registerContentsLayer(m_layer->layer()); | |
359 } | |
360 | |
361 return m_layer->layer(); | |
362 } | |
363 | |
364 void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer* imageBuffer) | |
365 { | |
366 if (!m_context || !m_context->makeContextCurrent() || m_context->extensions(
)->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR) | |
367 return; | |
368 | |
369 Extensions3D* extensions = m_context->extensions(); | |
370 | |
371 if (!imageBuffer) | |
372 return; | |
373 Platform3DObject tex = imageBuffer->getBackingTexture(); | |
374 if (tex) { | |
375 extensions->copyTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, m_frontCo
lorBuffer, | |
376 tex, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE); | |
377 return; | |
378 } | |
379 | |
380 // Since the m_frontColorBuffer was produced and sent to the compositor, it
cannot be bound to an fbo. | |
381 // We have to make a copy of it here and bind that copy instead. | |
382 // FIXME: That's not true any more, provided we don't change texture | |
383 // parameters. | |
384 unsigned sourceTexture = createColorTexture(m_size); | |
385 extensions->copyTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, m_frontColorB
uffer, sourceTexture, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BY
TE); | |
386 | |
387 // Since we're using the same context as WebGL, we have to restore any state
we change (in this case, just the framebuffer binding). | |
388 // FIXME: The WebGLRenderingContext tracks the current framebuffer binding,
it would be slightly more efficient to use this value | |
389 // rather than querying it off of the context. | |
390 GC3Dint previousFramebuffer = 0; | |
391 m_context->getIntegerv(GraphicsContext3D::FRAMEBUFFER_BINDING, &previousFram
ebuffer); | |
392 | |
393 Platform3DObject framebuffer = m_context->createFramebuffer(); | |
394 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, framebuffer); | |
395 m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsCont
ext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, sourceTexture, 0); | |
396 | |
397 extensions->paintFramebufferToCanvas(framebuffer, size().width(), size().hei
ght(), !m_attributes.premultipliedAlpha, imageBuffer); | |
398 m_context->deleteFramebuffer(framebuffer); | |
399 m_context->deleteTexture(sourceTexture); | |
400 | |
401 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, previousFramebuff
er); | |
402 } | |
403 | |
404 void DrawingBuffer::clearPlatformLayer() | |
405 { | |
406 if (m_layer) | |
407 m_layer->clearTexture(); | |
408 | |
409 if (m_context) | |
410 m_context->flush(); | |
411 } | |
412 | |
413 void DrawingBuffer::releaseResources() | |
414 { | |
415 if (m_context) { | |
416 m_context->makeContextCurrent(); | |
417 | |
418 clearPlatformLayer(); | |
419 | |
420 for (size_t i = 0; i < m_textureMailboxes.size(); i++) | |
421 m_context->deleteTexture(m_textureMailboxes[i]->textureId); | |
422 | |
423 if (m_multisampleColorBuffer) | |
424 m_context->deleteRenderbuffer(m_multisampleColorBuffer); | |
425 | |
426 if (m_depthStencilBuffer) | |
427 m_context->deleteRenderbuffer(m_depthStencilBuffer); | |
428 | |
429 if (m_depthBuffer) | |
430 m_context->deleteRenderbuffer(m_depthBuffer); | |
431 | |
432 if (m_stencilBuffer) | |
433 m_context->deleteRenderbuffer(m_stencilBuffer); | |
434 | |
435 if (m_multisampleFBO) | |
436 m_context->deleteFramebuffer(m_multisampleFBO); | |
437 | |
438 if (m_fbo) | |
439 m_context->deleteFramebuffer(m_fbo); | |
440 | |
441 m_context.clear(); | |
442 } | |
443 | |
444 setSize(IntSize()); | |
445 | |
446 m_colorBuffer = 0; | |
447 m_frontColorBuffer = 0; | |
448 m_multisampleColorBuffer = 0; | |
449 m_depthStencilBuffer = 0; | |
450 m_depthBuffer = 0; | |
451 m_stencilBuffer = 0; | |
452 m_multisampleFBO = 0; | |
453 m_fbo = 0; | |
454 m_contextEvictionManager.clear(); | |
455 | |
456 m_lastColorBuffer.clear(); | |
457 m_recycledMailboxes.clear(); | |
458 m_textureMailboxes.clear(); | |
459 | |
460 if (m_layer) { | |
461 GraphicsLayer::unregisterContentsLayer(m_layer->layer()); | |
462 m_layer.clear(); | |
463 } | |
464 } | |
465 | |
466 unsigned DrawingBuffer::createColorTexture(const IntSize& size) | |
467 { | |
468 if (!m_context) | |
469 return 0; | |
470 | |
471 unsigned offscreenColorTexture = m_context->createTexture(); | |
472 if (!offscreenColorTexture) | |
473 return 0; | |
474 | |
475 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, offscreenColorTexture)
; | |
476 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::T
EXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); | |
477 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::T
EXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); | |
478 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::T
EXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); | |
479 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::T
EXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); | |
480 if (!size.isEmpty()) | |
481 m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, m_in
ternalColorFormat, size.width(), size.height(), 0, m_colorFormat, GraphicsContex
t3D::UNSIGNED_BYTE); | |
482 | |
483 return offscreenColorTexture; | |
484 } | |
485 | |
486 void DrawingBuffer::createSecondaryBuffers() | |
487 { | |
488 // create a multisample FBO | |
489 if (multisample()) { | |
490 m_multisampleFBO = m_context->createFramebuffer(); | |
491 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisample
FBO); | |
492 m_multisampleColorBuffer = m_context->createRenderbuffer(); | |
493 } | |
494 } | |
495 | |
496 bool DrawingBuffer::resizeFramebuffer(const IntSize& size) | |
497 { | |
498 // resize regular FBO | |
499 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); | |
500 | |
501 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); | |
502 m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, m_intern
alColorFormat, size.width(), size.height(), 0, m_colorFormat, GraphicsContext3D:
:UNSIGNED_BYTE); | |
503 if (m_lastColorBuffer) | |
504 m_lastColorBuffer->size = m_size; | |
505 | |
506 m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsCont
ext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); | |
507 | |
508 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); | |
509 | |
510 if (!multisample()) | |
511 resizeDepthStencil(size, 0); | |
512 if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != Gra
phicsContext3D::FRAMEBUFFER_COMPLETE) | |
513 return false; | |
514 | |
515 return true; | |
516 } | |
517 | |
518 bool DrawingBuffer::resizeMultisampleFramebuffer(const IntSize& size) | |
519 { | |
520 if (multisample()) { | |
521 int maxSampleCount = 0; | |
522 | |
523 m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); | |
524 int sampleCount = std::min(4, maxSampleCount); | |
525 | |
526 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisample
FBO); | |
527 | |
528 m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisamp
leColorBuffer); | |
529 m_context->extensions()->renderbufferStorageMultisample(GraphicsContext3
D::RENDERBUFFER, sampleCount, m_internalRenderbufferFormat, size.width(), size.h
eight()); | |
530 | |
531 if (m_context->getError() == GraphicsContext3D::OUT_OF_MEMORY) | |
532 return false; | |
533 | |
534 m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, Graph
icsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleC
olorBuffer); | |
535 resizeDepthStencil(size, sampleCount); | |
536 if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) !=
GraphicsContext3D::FRAMEBUFFER_COMPLETE) | |
537 return false; | |
538 } | |
539 | |
540 return true; | |
541 } | |
542 | |
543 void DrawingBuffer::resizeDepthStencil(const IntSize& size, int sampleCount) | |
544 { | |
545 if (m_attributes.depth && m_attributes.stencil && m_packedDepthStencilExtens
ionSupported) { | |
546 if (!m_depthStencilBuffer) | |
547 m_depthStencilBuffer = m_context->createRenderbuffer(); | |
548 m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthSten
cilBuffer); | |
549 if (multisample()) | |
550 m_context->extensions()->renderbufferStorageMultisample(GraphicsCont
ext3D::RENDERBUFFER, sampleCount, Extensions3D::DEPTH24_STENCIL8, size.width(),
size.height()); | |
551 else | |
552 m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, Exte
nsions3D::DEPTH24_STENCIL8, size.width(), size.height()); | |
553 m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, Graph
icsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthStenci
lBuffer); | |
554 m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, Graph
icsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthStencilB
uffer); | |
555 } else { | |
556 if (m_attributes.depth) { | |
557 if (!m_depthBuffer) | |
558 m_depthBuffer = m_context->createRenderbuffer(); | |
559 m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depth
Buffer); | |
560 if (multisample()) | |
561 m_context->extensions()->renderbufferStorageMultisample(Graphics
Context3D::RENDERBUFFER, sampleCount, GraphicsContext3D::DEPTH_COMPONENT16, size
.width(), size.height()); | |
562 else | |
563 m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER,
GraphicsContext3D::DEPTH_COMPONENT16, size.width(), size.height()); | |
564 m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, G
raphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuff
er); | |
565 } | |
566 if (m_attributes.stencil) { | |
567 if (!m_stencilBuffer) | |
568 m_stencilBuffer = m_context->createRenderbuffer(); | |
569 m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_stenc
ilBuffer); | |
570 if (multisample()) | |
571 m_context->extensions()->renderbufferStorageMultisample(Graphics
Context3D::RENDERBUFFER, sampleCount, GraphicsContext3D::STENCIL_INDEX8, size.wi
dth(), size.height()); | |
572 else | |
573 m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER,
GraphicsContext3D::STENCIL_INDEX8, size.width(), size.height()); | |
574 m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, G
raphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_stencil
Buffer); | |
575 } | |
576 } | |
577 m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); | |
578 } | |
579 | |
580 | |
581 | |
582 void DrawingBuffer::clearFramebuffers(GC3Dbitfield clearMask) | |
583 { | |
584 if (!m_context) | |
585 return; | |
586 | |
587 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO
? m_multisampleFBO : m_fbo); | |
588 | |
589 m_context->clear(clearMask); | |
590 | |
591 // The multisample fbo was just cleared, but we also need to clear the non-m
ultisampled buffer too. | |
592 if (m_multisampleFBO) { | |
593 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); | |
594 m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); | |
595 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisample
FBO); | |
596 } | |
597 } | |
598 | |
599 void DrawingBuffer::setSize(const IntSize& size) { | |
600 if (m_size == size) | |
601 return; | |
602 | |
603 s_currentResourceUsePixels += pixelDelta(size); | |
604 m_size = size; | |
605 } | |
606 | |
607 int DrawingBuffer::pixelDelta(const IntSize& size) { | |
608 return (max(0, size.width()) * max(0, size.height())) - (max(0, m_size.width
()) * max(0, m_size.height())); | |
609 } | |
610 | |
611 IntSize DrawingBuffer::adjustSize(const IntSize& size) { | |
612 IntSize adjustedSize = size; | |
613 | |
614 // Clamp if the desired size is greater than the maximum texture size for th
e device. | |
615 if (adjustedSize.height() > m_maxTextureSize) | |
616 adjustedSize.setHeight(m_maxTextureSize); | |
617 | |
618 if (adjustedSize.width() > m_maxTextureSize) | |
619 adjustedSize.setWidth(m_maxTextureSize); | |
620 | |
621 // Try progressively smaller sizes until we find a size that fits or reach a
scale limit. | |
622 int scaleAttempts = 0; | |
623 while ((s_currentResourceUsePixels + pixelDelta(adjustedSize)) > s_maximumRe
sourceUsePixels) { | |
624 scaleAttempts++; | |
625 if (scaleAttempts > s_maxScaleAttempts) | |
626 return IntSize(); | |
627 | |
628 adjustedSize.scale(s_resourceAdjustedRatio); | |
629 | |
630 if (adjustedSize.isEmpty()) | |
631 return IntSize(); | |
632 } | |
633 | |
634 return adjustedSize; | |
635 } | |
636 | |
637 IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool&
evictContext) { | |
638 IntSize adjustedSize = adjustSize(size); | |
639 if (!adjustedSize.isEmpty()) { | |
640 evictContext = false; | |
641 return adjustedSize; // Buffer fits without evicting a context. | |
642 } | |
643 | |
644 // Speculatively adjust the pixel budget to see if the buffer would fit shou
ld the oldest context be evicted. | |
645 IntSize oldestSize = m_contextEvictionManager->oldestContextSize(); | |
646 int pixelDelta = oldestSize.width() * oldestSize.height(); | |
647 | |
648 s_currentResourceUsePixels -= pixelDelta; | |
649 adjustedSize = adjustSize(size); | |
650 s_currentResourceUsePixels += pixelDelta; | |
651 | |
652 evictContext = !adjustedSize.isEmpty(); | |
653 return adjustedSize; | |
654 } | |
655 | |
656 void DrawingBuffer::reset(const IntSize& newSize) | |
657 { | |
658 if (!m_context) | |
659 return; | |
660 | |
661 IntSize adjustedSize; | |
662 bool evictContext = false; | |
663 bool isNewContext = m_size.isEmpty(); | |
664 if (s_allowContextEvictionOnCreate && isNewContext) | |
665 adjustedSize = adjustSizeWithContextEviction(newSize, evictContext); | |
666 else | |
667 adjustedSize = adjustSize(newSize); | |
668 | |
669 if (adjustedSize.isEmpty()) | |
670 return; | |
671 | |
672 if (evictContext) | |
673 m_contextEvictionManager->forciblyLoseOldestContext("WARNING: WebGL cont
exts have exceeded the maximum allowed backbuffer area. Oldest context will be l
ost."); | |
674 | |
675 if (adjustedSize != m_size) { | |
676 do { | |
677 // resize multisample FBO | |
678 if (!resizeMultisampleFramebuffer(adjustedSize) || !resizeFramebuffe
r(adjustedSize)) { | |
679 adjustedSize.scale(s_resourceAdjustedRatio); | |
680 continue; | |
681 } | |
682 break; | |
683 } while (!adjustedSize.isEmpty()); | |
684 | |
685 setSize(adjustedSize); | |
686 | |
687 if (adjustedSize.isEmpty()) | |
688 return; | |
689 } | |
690 | |
691 m_context->disable(GraphicsContext3D::SCISSOR_TEST); | |
692 m_context->clearColor(0, 0, 0, 0); | |
693 m_context->colorMask(true, true, true, true); | |
694 | |
695 GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT; | |
696 if (m_attributes.depth) { | |
697 m_context->clearDepth(1.0f); | |
698 clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; | |
699 m_context->depthMask(true); | |
700 } | |
701 if (m_attributes.stencil) { | |
702 m_context->clearStencil(0); | |
703 clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; | |
704 m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF); | |
705 } | |
706 | |
707 clearFramebuffers(clearMask); | |
708 } | |
709 | |
710 void DrawingBuffer::commit(long x, long y, long width, long height) | |
711 { | |
712 if (!m_context) | |
713 return; | |
714 | |
715 if (width < 0) | |
716 width = m_size.width(); | |
717 if (height < 0) | |
718 height = m_size.height(); | |
719 | |
720 m_context->makeContextCurrent(); | |
721 | |
722 if (m_multisampleFBO && !m_contentsChangeCommitted) { | |
723 m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisample
FBO); | |
724 m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_fbo); | |
725 | |
726 if (m_scissorEnabled) | |
727 m_context->disable(GraphicsContext3D::SCISSOR_TEST); | |
728 | |
729 // Use NEAREST, because there is no scale performed during the blit. | |
730 m_context->extensions()->blitFramebuffer(x, y, width, height, x, y, widt
h, height, GraphicsContext3D::COLOR_BUFFER_BIT, GraphicsContext3D::NEAREST); | |
731 | |
732 if (m_scissorEnabled) | |
733 m_context->enable(GraphicsContext3D::SCISSOR_TEST); | |
734 } | |
735 | |
736 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); | |
737 m_contentsChangeCommitted = true; | |
738 } | |
739 | |
740 void DrawingBuffer::restoreFramebufferBinding() | |
741 { | |
742 if (!m_context || !m_framebufferBinding) | |
743 return; | |
744 | |
745 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_framebufferBind
ing); | |
746 } | |
747 | |
748 bool DrawingBuffer::multisample() const | |
749 { | |
750 return m_attributes.antialias && m_multisampleExtensionSupported; | |
751 } | |
752 | |
753 void DrawingBuffer::bind() | |
754 { | |
755 if (!m_context) | |
756 return; | |
757 | |
758 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO
? m_multisampleFBO : m_fbo); | |
759 } | |
760 | |
761 } // namespace WebCore | |
OLD | NEW |