/* * Copyright (c) 2010, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SKY_ENGINE_PLATFORM_GRAPHICS_GPU_DRAWINGBUFFER_H_ #define SKY_ENGINE_PLATFORM_GRAPHICS_GPU_DRAWINGBUFFER_H_ #include "sky/engine/platform/PlatformExport.h" #include "sky/engine/platform/geometry/IntSize.h" #include "sky/engine/platform/graphics/GraphicsTypes3D.h" #include "sky/engine/platform/graphics/gpu/WebGLImageConversion.h" #include "sky/engine/public/platform/WebExternalTextureLayerClient.h" #include "sky/engine/public/platform/WebExternalTextureMailbox.h" #include "sky/engine/public/platform/WebGraphicsContext3D.h" #include "sky/engine/wtf/Deque.h" #include "sky/engine/wtf/Noncopyable.h" #include "sky/engine/wtf/OwnPtr.h" #include "sky/engine/wtf/PassOwnPtr.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "third_party/skia/include/core/SkBitmap.h" namespace blink { class Extensions3DUtil; class ImageBuffer; class WebExternalBitmap; class WebExternalTextureLayer; class WebGraphicsContext3D; class WebLayer; // Abstract interface to allow basic context eviction management class PLATFORM_EXPORT ContextEvictionManager : public RefCounted { public: virtual ~ContextEvictionManager() {}; virtual void forciblyLoseOldestContext(const String& reason) = 0; virtual IntSize oldestContextSize() = 0; }; // Manages a rendering target (framebuffer + attachment) for a canvas. Can publish its rendering // results to a WebLayer for compositing. class PLATFORM_EXPORT DrawingBuffer : public RefCounted, public WebExternalTextureLayerClient { // If we used CHROMIUM_image as the backing storage for our buffers, // we need to know the mapping from texture id to image. struct TextureInfo { Platform3DObject textureId; WGC3Duint imageId; TextureInfo() : textureId(0) , imageId(0) { } }; struct MailboxInfo : public RefCounted { WebExternalTextureMailbox mailbox; TextureInfo textureInfo; IntSize size; // This keeps the parent drawing buffer alive as long as the compositor is // referring to one of the mailboxes DrawingBuffer produced. The parent drawing buffer is // cleared when the compositor returns the mailbox. See mailboxReleased(). RefPtr m_parentDrawingBuffer; }; public: enum PreserveDrawingBuffer { Preserve, Discard }; static PassRefPtr create(PassOwnPtr, const IntSize&, PreserveDrawingBuffer, WebGraphicsContext3D::Attributes requestedAttributes, PassRefPtr); virtual ~DrawingBuffer(); // Destruction will be completed after all mailboxes are released. void beginDestruction(); // Issues a glClear() on all framebuffers associated with this DrawingBuffer. The caller is responsible for // making the context current and setting the clear values and masks. Modifies the framebuffer binding. void clearFramebuffers(GLbitfield clearMask); // Given the desired buffer size, provides the largest dimensions that will fit in the pixel budget. static IntSize adjustSize(const IntSize& desiredSize, const IntSize& curSize, int maxTextureSize); bool reset(const IntSize&); void bind(); IntSize size() const { return m_size; } // Copies the multisample color buffer to the normal color buffer and leaves m_fbo bound. void commit(long x = 0, long y = 0, long width = -1, long height = -1); // commit should copy the full multisample buffer, and not respect the // current scissor bounds. Track the state of the scissor test so that it // can be disabled during calls to commit. void setScissorEnabled(bool scissorEnabled) { m_scissorEnabled = scissorEnabled; } // The DrawingBuffer needs to track the texture bound to texture unit 0. // The bound texture is tracked to avoid costly queries during rendering. void setTexture2DBinding(Platform3DObject texture) { m_texture2DBinding = texture; } // The DrawingBuffer needs to track the currently bound framebuffer so it // restore the binding when needed. void setFramebufferBinding(Platform3DObject fbo) { m_framebufferBinding = fbo; } // Track the currently active texture unit. Texture unit 0 is used as host for a scratch // texture. void setActiveTextureUnit(GLint textureUnit) { m_activeTextureUnit = textureUnit; } bool multisample() const; Platform3DObject framebuffer() const; void markContentsChanged(); void markLayerComposited(); bool layerComposited() const; void setIsHidden(bool); WebLayer* platformLayer(); void paintCompositedResultsToCanvas(ImageBuffer*); WebGraphicsContext3D* context(); // Returns the actual context attributes for this drawing buffer which may differ from the // requested context attributes due to implementation limits. WebGraphicsContext3D::Attributes getActualAttributes() const { return m_actualAttributes; } // WebExternalTextureLayerClient implementation. virtual bool prepareMailbox(WebExternalTextureMailbox*, WebExternalBitmap*) override; virtual void mailboxReleased(const WebExternalTextureMailbox&, bool lostResource = false) override; // Destroys the TEXTURE_2D binding for the owned context bool copyToPlatformTexture(WebGraphicsContext3D*, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY, bool fromFrontBuffer = false); void setPackAlignment(GLint param); void paintRenderingResultsToCanvas(ImageBuffer*); PassRefPtr paintRenderingResultsToImageData(int&, int&); protected: // For unittests DrawingBuffer( PassOwnPtr, PassOwnPtr, bool multisampleExtensionSupported, bool packedDepthStencilExtensionSupported, PreserveDrawingBuffer, WebGraphicsContext3D::Attributes requestedAttributes, PassRefPtr); bool initialize(const IntSize&); private: void mailboxReleasedWithoutRecycling(const WebExternalTextureMailbox&); unsigned createColorTexture(); // Create the depth/stencil and multisample buffers, if needed. void createSecondaryBuffers(); bool resizeFramebuffer(const IntSize&); bool resizeMultisampleFramebuffer(const IntSize&); void resizeDepthStencil(const IntSize&); // Bind to the m_framebufferBinding if it's not 0. void restoreFramebufferBinding(); void clearPlatformLayer(); PassRefPtr recycledMailbox(); PassRefPtr createNewMailbox(const TextureInfo&); void deleteMailbox(const WebExternalTextureMailbox&); void freeRecycledMailboxes(); // Updates the current size of the buffer, ensuring that s_currentResourceUsePixels is updated. void setSize(const IntSize& size); // Calculates the difference in pixels between the current buffer size and the proposed size. static int pixelDelta(const IntSize& newSize, const IntSize& curSize); // Given the desired buffer size, provides the largest dimensions that will fit in the pixel budget // Returns true if the buffer will only fit if the oldest WebGL context is forcibly lost IntSize adjustSizeWithContextEviction(const IntSize&, bool& evictContext); void paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer*); // This is the order of bytes to use when doing a readback. enum ReadbackOrder { ReadbackRGBA, ReadbackSkia }; // Helper function which does a readback from the currently-bound // framebuffer into a buffer of a certain size with 4-byte pixels. void readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder, WebGLImageConversion::AlphaOp); // Helper function to flip a bitmap vertically. void flipVertically(uint8_t* data, int width, int height); // Helper to texImage2D with pixel==0 case: pixels are initialized to 0. // By default, alignment is 4, the OpenGL default setting. void texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint alignment = 4); // Allocate buffer storage to be sent to compositor using either texImage2D or CHROMIUM_image based on available support. void allocateTextureMemory(TextureInfo*, const IntSize&); void deleteChromiumImageForTexture(TextureInfo*); PreserveDrawingBuffer m_preserveDrawingBuffer; bool m_scissorEnabled; Platform3DObject m_texture2DBinding; Platform3DObject m_framebufferBinding; GLenum m_activeTextureUnit; OwnPtr m_context; OwnPtr m_extensionsUtil; IntSize m_size; WebGraphicsContext3D::Attributes m_requestedAttributes; bool m_multisampleExtensionSupported; bool m_packedDepthStencilExtensionSupported; Platform3DObject m_fbo; // DrawingBuffer's output is double-buffered. m_colorBuffer is the back buffer. TextureInfo m_colorBuffer; TextureInfo m_frontColorBuffer; // This is used when we have OES_packed_depth_stencil. Platform3DObject m_depthStencilBuffer; // These are used when we don't. Platform3DObject m_depthBuffer; Platform3DObject m_stencilBuffer; // For multisampling. Platform3DObject m_multisampleFBO; Platform3DObject m_multisampleColorBuffer; // True if our contents have been modified since the last presentation of this buffer. bool m_contentsChanged; // True if commit() has been called since the last time markContentsChanged() had been called. bool m_contentsChangeCommitted; bool m_layerComposited; enum MultisampleMode { None, ImplicitResolve, ExplicitResolve, }; MultisampleMode m_multisampleMode; WebGraphicsContext3D::Attributes m_actualAttributes; unsigned m_internalColorFormat; unsigned m_colorFormat; unsigned m_internalRenderbufferFormat; int m_maxTextureSize; int m_sampleCount; int m_packAlignment; bool m_destructionInProgress; bool m_isHidden; OwnPtr m_layer; // All of the mailboxes that this DrawingBuffer has ever created. Vector > m_textureMailboxes; // Mailboxes that were released by the compositor can be used again by this DrawingBuffer. Deque m_recycledMailboxQueue; RefPtr m_contextEvictionManager; // If the width and height of the Canvas's backing store don't // match those that we were given in the most recent call to // reshape(), then we need an intermediate bitmap to read back the // frame buffer into. This seems to happen when CSS styles are // used to resize the Canvas. SkBitmap m_resizingBitmap; // Used to flip a bitmap vertically. Vector m_scanline; }; } // namespace blink #endif // SKY_ENGINE_PLATFORM_GRAPHICS_GPU_DRAWINGBUFFER_H_