blob: 44fa609885cf0e079b7e5463cd65ab5d298a5a49 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/shader_manager.h"
#include "gpu/gpu_gles2_export.h"
namespace gpu {
namespace gles2 {
class FeatureInfo;
class FramebufferCompletenessCache;
class FramebufferManager;
class Renderbuffer;
class RenderbufferManager;
class TextureRef;
class TextureManager;
// Info about a particular Framebuffer.
class GPU_GLES2_EXPORT Framebuffer : public base::RefCounted<Framebuffer> {
class Attachment : public base::RefCounted<Attachment> {
virtual GLsizei width() const = 0;
virtual GLsizei height() const = 0;
virtual GLenum internal_format() const = 0;
virtual GLenum texture_type() const = 0;
virtual GLsizei samples() const = 0;
virtual GLuint object_name() const = 0;
virtual GLint level() const = 0;
virtual bool cleared() const = 0;
virtual void SetCleared(
RenderbufferManager* renderbuffer_manager,
TextureManager* texture_manager,
bool cleared) = 0;
virtual bool IsPartiallyCleared() const = 0;
virtual bool IsTextureAttachment() const = 0;
virtual bool IsRenderbufferAttachment() const = 0;
virtual bool IsTexture(TextureRef* texture) const = 0;
virtual bool IsRenderbuffer(Renderbuffer* renderbuffer) const = 0;
virtual bool IsSameAttachment(const Attachment* attachment) const = 0;
virtual bool Is3D() const = 0;
// If it's a 3D texture attachment, return true if
// FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER is smaller than the number of
// layers in the texture.
virtual bool IsLayerValid() const = 0;
virtual bool CanRenderTo(const FeatureInfo* feature_info) const = 0;
virtual void DetachFromFramebuffer(Framebuffer* framebuffer,
GLenum attachment) const = 0;
virtual bool ValidForAttachmentType(GLenum attachment_type,
uint32_t max_color_attachments) = 0;
virtual size_t GetSignatureSize(TextureManager* texture_manager) const = 0;
virtual void AddToSignature(
TextureManager* texture_manager, std::string* signature) const = 0;
virtual bool FormsFeedbackLoop(
TextureRef* texture, GLint level, GLint layer) const = 0;
virtual bool EmulatingRGB() const = 0;
friend class base::RefCounted<Attachment>;
virtual ~Attachment() = default;
Framebuffer(FramebufferManager* manager, GLuint service_id);
GLuint service_id() const {
return service_id_;
bool HasUnclearedAttachment(GLenum attachment) const;
bool HasUnclearedColorAttachments() const;
bool HasSRGBAttachments() const;
bool HasDepthStencilFormatAttachment() const;
void ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
GLES2Decoder* decoder,
TextureManager* texture_manager);
bool HasUnclearedIntRenderbufferAttachments() const;
void ClearUnclearedIntRenderbufferAttachments(
RenderbufferManager* renderbuffer_manager);
void MarkAttachmentAsCleared(
RenderbufferManager* renderbuffer_manager,
TextureManager* texture_manager,
GLenum attachment,
bool cleared);
// Unbinds all attachments from this framebuffer for workaround
// 'unbind_attachments_on_bound_render_fbo_delete'. The Framebuffer must be
// bound when calling this.
void DoUnbindGLAttachmentsForWorkaround(GLenum target);
// Attaches a renderbuffer to a particlar attachment.
// Pass null to detach.
void AttachRenderbuffer(
GLenum attachment, Renderbuffer* renderbuffer);
// Attaches a texture to a particlar attachment. Pass null to detach.
void AttachTexture(
GLenum attachment, TextureRef* texture_ref, GLenum target,
GLint level, GLsizei samples);
void AttachTextureLayer(
GLenum attachment, TextureRef* texture_ref, GLenum target,
GLint level, GLint layer);
// Unbinds the given renderbuffer if it is bound.
void UnbindRenderbuffer(
GLenum target, Renderbuffer* renderbuffer);
// Unbinds the given texture if it is bound.
void UnbindTexture(
GLenum target, TextureRef* texture_ref);
const Attachment* GetAttachment(GLenum attachment) const;
const Attachment* GetReadBufferAttachment() const;
// Returns the max dimensions which fit inside all of the attachments.
// Can only be called after the framebuffer has been checked to be complete.
gfx::Size GetFramebufferValidSize() const;
GLsizei GetSamples() const;
bool IsDeleted() const {
return deleted_;
void MarkAsValid() {
has_been_bound_ = true;
bool IsValid() const {
return has_been_bound_ && !IsDeleted();
bool HasColorAttachment(int index) const;
bool HasDepthAttachment() const;
bool HasStencilAttachment() const;
GLenum GetDepthFormat() const;
GLenum GetStencilFormat() const;
GLenum GetDrawBufferInternalFormat() const;
GLenum GetReadBufferInternalFormat() const;
// If the color attachment is a texture, returns its type; otherwise,
// returns 0.
GLenum GetReadBufferTextureType() const;
bool GetReadBufferIsMultisampledTexture() const;
// Verify all the rules in OpenGL ES 2.0.25 4.4.5 are followed.
// Returns GL_FRAMEBUFFER_COMPLETE if there are no reasons we know we can't
// use this combination of attachments. Otherwise returns the value
// that glCheckFramebufferStatus should return for this set of attachments.
// Note that receiving GL_FRAMEBUFFER_COMPLETE from this function does
// not mean the real OpenGL will consider it framebuffer complete. It just
// means it passed our tests.
GLenum IsPossiblyComplete(const FeatureInfo* feature_info) const;
// Implements optimized glGetFramebufferStatus.
GLenum GetStatus(TextureManager* texture_manager, GLenum target) const;
// Check all attachments are cleared
bool IsCleared() const;
GLenum GetDrawBuffer(GLenum draw_buffer) const;
void SetDrawBuffers(GLsizei n, const GLenum* bufs);
// If a color buffer is attached to GL_COLOR_ATTACHMENTi, enable that
// draw buffer for glClear().
// Return true if the DrawBuffers() is actually called.
bool PrepareDrawBuffersForClearingUninitializedAttachments() const;
// Restore |adjusted_draw_buffers_|.
void RestoreDrawBuffers() const;
// Checks if a draw buffer's format and its corresponding fragment shader
// output's type are compatible, i.e., a signed integer typed variable is
// incompatible with a float or unsigned integer buffer.
// Return false if incompaticle.
// Otherwise, filter out the draw buffers that are not written to but are not
// NONE through DrawBuffers, to be on the safe side. Return true.
// This is applied before a draw call.
bool ValidateAndAdjustDrawBuffers(uint32_t fragment_output_type_mask,
uint32_t fragment_output_written_mask);
// Filter out the draw buffers that have no images attached but are not NONE
// through DrawBuffers, to be on the safe side.
// This is applied before a clear call.
void AdjustDrawBuffers();
bool ContainsActiveIntegerAttachments() const;
// Return true if any draw buffers has an alpha channel.
bool HasAlphaMRT() const;
// Return false if any two active color attachments have different internal
// formats.
bool HasSameInternalFormatsMRT() const;
void set_read_buffer(GLenum read_buffer) {
read_buffer_ = read_buffer;
GLenum read_buffer() const {
return read_buffer_;
// See member declaration for details.
// The data are only valid if fbo is complete.
uint32_t draw_buffer_type_mask() const {
return draw_buffer_type_mask_;
uint32_t draw_buffer_bound_mask() const {
return draw_buffer_bound_mask_;
void UnmarkAsComplete() { framebuffer_complete_state_count_id_ = 0; }
friend class FramebufferManager;
friend class base::RefCounted<Framebuffer>;
void MarkAsDeleted();
void MarkAttachmentsAsCleared(
RenderbufferManager* renderbuffer_manager,
TextureManager* texture_manager,
bool cleared);
void MarkAsComplete(unsigned state_id) {
framebuffer_complete_state_count_id_ = state_id;
unsigned framebuffer_complete_state_count_id() const {
return framebuffer_complete_state_count_id_;
// Cache color attachments' base type mask (FLOAT, INT, UINT) and bound mask.
// If an attachment point has no image, it's set as UNDEFINED_TYPE.
// This call is only valid on a complete fbo.
void UpdateDrawBufferMasks();
// Helper for ValidateAndAdjustDrawBuffers() and AdjustDrawBuffers().
void AdjustDrawBuffersImpl(uint32_t desired_mask);
// The managers that owns this.
FramebufferManager* manager_;
bool deleted_;
// Service side framebuffer id.
GLuint service_id_;
// Whether this framebuffer has ever been bound.
bool has_been_bound_;
// state count when this framebuffer was last checked for completeness.
unsigned framebuffer_complete_state_count_id_;
// A map of attachments.
typedef base::hash_map<GLenum, scoped_refptr<Attachment> > AttachmentMap;
AttachmentMap attachments_;
// User's draw buffers setting through DrawBuffers() call.
std::unique_ptr<GLenum[]> draw_buffers_;
// If a draw buffer does not have an image, or it has no corresponding
// fragment shader output variable, it might be filtered out as NONE.
// Note that the actually draw buffers setting sent to the driver is always
// consistent with |adjusted_draw_buffers_|, not |draw_buffers_|.
std::unique_ptr<GLenum[]> adjusted_draw_buffers_;
// Draw buffer base types: FLOAT, INT, or UINT.
// We have up to 16 draw buffers, each is encoded into 2 bits, total 32 bits:
// the lowest 2 bits for draw buffer 0, the highest 2 bits for draw buffer 15.
uint32_t draw_buffer_type_mask_;
// Same layout as above, 2 bits per draw buffer, 0x03 if a draw buffer has a
// bound image, 0x00 if not.
uint32_t draw_buffer_bound_mask_;
// This is the mask for the actual draw buffers sent to driver.
uint32_t adjusted_draw_buffer_bound_mask_;
GLenum read_buffer_;
struct DecoderFramebufferState {
// State saved for clearing so we can clear render buffers and then
// restore to these values.
bool clear_state_dirty;
// The currently bound framebuffers
scoped_refptr<Framebuffer> bound_read_framebuffer;
scoped_refptr<Framebuffer> bound_draw_framebuffer;
// This class keeps track of the frambebuffers and their attached renderbuffers
// so we can correctly clear them.
class GPU_GLES2_EXPORT FramebufferManager {
uint32_t max_draw_buffers,
uint32_t max_color_attachments,
FramebufferCompletenessCache* framebuffer_combo_complete_cache);
// Must call before destruction.
void Destroy(bool have_context);
// Creates a Framebuffer for the given framebuffer.
void CreateFramebuffer(GLuint client_id, GLuint service_id);
// Gets the framebuffer info for the given framebuffer.
Framebuffer* GetFramebuffer(GLuint client_id);
// Removes a framebuffer info for the given framebuffer.
void RemoveFramebuffer(GLuint client_id);
// Gets a client id for a given service id.
bool GetClientId(GLuint service_id, GLuint* client_id) const;
void MarkAttachmentsAsCleared(
Framebuffer* framebuffer,
RenderbufferManager* renderbuffer_manager,
TextureManager* texture_manager);
void MarkAsComplete(Framebuffer* framebuffer);
bool IsComplete(const Framebuffer* framebuffer);
void IncFramebufferStateChangeCount() {
// make sure this is never 0.
framebuffer_state_change_count_ =
(framebuffer_state_change_count_ + 1) | 0x80000000U;
friend class Framebuffer;
void StartTracking(Framebuffer* framebuffer);
void StopTracking(Framebuffer* framebuffer);
FramebufferCompletenessCache* GetFramebufferComboCompleteCache() {
return framebuffer_combo_complete_cache_;
// Info for each framebuffer in the system.
typedef base::hash_map<GLuint, scoped_refptr<Framebuffer> >
FramebufferMap framebuffers_;
// Incremented anytime anything changes that might effect framebuffer
// state.
unsigned framebuffer_state_change_count_;
// Counts the number of Framebuffer allocated with 'this' as its manager.
// Allows to check no Framebuffer will outlive this.
unsigned int framebuffer_count_;
bool have_context_;
uint32_t max_draw_buffers_;
uint32_t max_color_attachments_;
FramebufferCompletenessCache* framebuffer_combo_complete_cache_;
} // namespace gles2
} // namespace gpu