blob: 22322b92779c17ed4cfc9f08acfb72dd16c28c11 [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 "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include <stdio.h>
#include <algorithm>
#include <list>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include "base/at_exit.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/float_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/numerics/safe_math.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_synthetic_delay.h"
#include "build/build_config.h"
#define GLES2_GPU_SERVICE 1
#include "gpu/command_buffer/common/debug_marker_manager.h"
#include "gpu/command_buffer/common/gles2_cmd_format.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/common/id_allocator.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
#include "gpu/command_buffer/service/buffer_manager.h"
#include "gpu/command_buffer/service/cmd_buffer_engine.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/context_state.h"
#include "gpu/command_buffer/service/error_state.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/framebuffer_manager.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h"
#include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
#include "gpu/command_buffer/service/gles2_cmd_validation.h"
#include "gpu/command_buffer/service/gpu_state_tracer.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/gpu_tracer.h"
#include "gpu/command_buffer/service/image_manager.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/command_buffer/service/program_manager.h"
#include "gpu/command_buffer/service/query_manager.h"
#include "gpu/command_buffer/service/renderbuffer_manager.h"
#include "gpu/command_buffer/service/shader_manager.h"
#include "gpu/command_buffer/service/shader_translator.h"
#include "gpu/command_buffer/service/shader_translator_cache.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "gpu/command_buffer/service/vertex_array_manager.h"
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
#include "third_party/smhasher/src/City.h"
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_image.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
#if defined(OS_MACOSX)
#include <IOSurface/IOSurfaceAPI.h>
// Note that this must be included after gl_bindings.h to avoid conflicts.
#include <OpenGL/CGLIOSurface.h>
#endif
#if defined(OS_WIN)
#include "base/win/win_util.h"
#endif
namespace gpu {
namespace gles2 {
namespace {
static const char kOESDerivativeExtension[] = "GL_OES_standard_derivatives";
static const char kEXTFragDepthExtension[] = "GL_EXT_frag_depth";
static const char kEXTDrawBuffersExtension[] = "GL_EXT_draw_buffers";
static const char kEXTShaderTextureLodExtension[] = "GL_EXT_shader_texture_lod";
static bool PrecisionMeetsSpecForHighpFloat(GLint rangeMin,
GLint rangeMax,
GLint precision) {
return (rangeMin >= 62) && (rangeMax >= 62) && (precision >= 16);
}
static void GetShaderPrecisionFormatImpl(GLenum shader_type,
GLenum precision_type,
GLint *range, GLint *precision) {
switch (precision_type) {
case GL_LOW_INT:
case GL_MEDIUM_INT:
case GL_HIGH_INT:
// These values are for a 32-bit twos-complement integer format.
range[0] = 31;
range[1] = 30;
*precision = 0;
break;
case GL_LOW_FLOAT:
case GL_MEDIUM_FLOAT:
case GL_HIGH_FLOAT:
// These values are for an IEEE single-precision floating-point format.
range[0] = 127;
range[1] = 127;
*precision = 23;
break;
default:
NOTREACHED();
break;
}
if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
gfx::g_driver_gl.fn.glGetShaderPrecisionFormatFn) {
// This function is sometimes defined even though it's really just
// a stub, so we need to set range and precision as if it weren't
// defined before calling it.
// On Mac OS with some GPUs, calling this generates a
// GL_INVALID_OPERATION error. Avoid calling it on non-GLES2
// platforms.
glGetShaderPrecisionFormat(shader_type, precision_type,
range, precision);
// TODO(brianderson): Make the following official workarounds.
// Some drivers have bugs where they report the ranges as a negative number.
// Taking the absolute value here shouldn't hurt because negative numbers
// aren't expected anyway.
range[0] = abs(range[0]);
range[1] = abs(range[1]);
// If the driver reports a precision for highp float that isn't actually
// highp, don't pretend like it's supported because shader compilation will
// fail anyway.
if (precision_type == GL_HIGH_FLOAT &&
!PrecisionMeetsSpecForHighpFloat(range[0], range[1], *precision)) {
range[0] = 0;
range[1] = 0;
*precision = 0;
}
}
}
static gfx::OverlayTransform GetGFXOverlayTransform(GLenum plane_transform) {
switch (plane_transform) {
case GL_OVERLAY_TRANSFORM_NONE_CHROMIUM:
return gfx::OVERLAY_TRANSFORM_NONE;
case GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM:
return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
case GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM:
return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
case GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM:
return gfx::OVERLAY_TRANSFORM_ROTATE_90;
case GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM:
return gfx::OVERLAY_TRANSFORM_ROTATE_180;
case GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM:
return gfx::OVERLAY_TRANSFORM_ROTATE_270;
default:
return gfx::OVERLAY_TRANSFORM_INVALID;
}
}
} // namespace
class GLES2DecoderImpl;
// Local versions of the SET_GL_ERROR macros
#define LOCAL_SET_GL_ERROR(error, function_name, msg) \
ERRORSTATE_SET_GL_ERROR(state_.GetErrorState(), error, function_name, msg)
#define LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, value, label) \
ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(state_.GetErrorState(), \
function_name, value, label)
#define LOCAL_SET_GL_ERROR_INVALID_PARAM(error, function_name, pname) \
ERRORSTATE_SET_GL_ERROR_INVALID_PARAM(state_.GetErrorState(), error, \
function_name, pname)
#define LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(function_name) \
ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(state_.GetErrorState(), \
function_name)
#define LOCAL_PEEK_GL_ERROR(function_name) \
ERRORSTATE_PEEK_GL_ERROR(state_.GetErrorState(), function_name)
#define LOCAL_CLEAR_REAL_GL_ERRORS(function_name) \
ERRORSTATE_CLEAR_REAL_GL_ERRORS(state_.GetErrorState(), function_name)
#define LOCAL_PERFORMANCE_WARNING(msg) \
PerformanceWarning(__FILE__, __LINE__, msg)
#define LOCAL_RENDER_WARNING(msg) \
RenderWarning(__FILE__, __LINE__, msg)
// Check that certain assumptions the code makes are true. There are places in
// the code where shared memory is passed direclty to GL. Example, glUniformiv,
// glShaderSource. The command buffer code assumes GLint and GLsizei (and maybe
// a few others) are 32bits. If they are not 32bits the code will have to change
// to call those GL functions with service side memory and then copy the results
// to shared memory, converting the sizes.
static_assert(sizeof(GLint) == sizeof(uint32), // NOLINT
"GLint should be the same size as uint32");
static_assert(sizeof(GLsizei) == sizeof(uint32), // NOLINT
"GLsizei should be the same size as uint32");
static_assert(sizeof(GLfloat) == sizeof(float), // NOLINT
"GLfloat should be the same size as float");
// TODO(kbr): the use of this anonymous namespace core dumps the
// linker on Mac OS X 10.6 when the symbol ordering file is used
// namespace {
// Returns the address of the first byte after a struct.
template <typename T>
const void* AddressAfterStruct(const T& pod) {
return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
}
// Returns the address of the frst byte after the struct or NULL if size >
// immediate_data_size.
template <typename RETURN_TYPE, typename COMMAND_TYPE>
RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod,
uint32 size,
uint32 immediate_data_size) {
return (size <= immediate_data_size) ?
static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod))) :
NULL;
}
// Computes the data size for certain gl commands like glUniform.
bool ComputeDataSize(
GLuint count,
size_t size,
unsigned int elements_per_unit,
uint32* dst) {
uint32 value;
if (!SafeMultiplyUint32(count, size, &value)) {
return false;
}
if (!SafeMultiplyUint32(value, elements_per_unit, &value)) {
return false;
}
*dst = value;
return true;
}
// Return true if a character belongs to the ASCII subset as defined in
// GLSL ES 1.0 spec section 3.1.
static bool CharacterIsValidForGLES(unsigned char c) {
// Printing characters are valid except " $ ` @ \ ' DEL.
if (c >= 32 && c <= 126 &&
c != '"' &&
c != '$' &&
c != '`' &&
c != '@' &&
c != '\\' &&
c != '\'') {
return true;
}
// Horizontal tab, line feed, vertical tab, form feed, carriage return
// are also valid.
if (c >= 9 && c <= 13) {
return true;
}
return false;
}
static bool StringIsValidForGLES(const char* str) {
for (; *str; ++str) {
if (!CharacterIsValidForGLES(*str)) {
return false;
}
}
return true;
}
// This class prevents any GL errors that occur when it is in scope from
// being reported to the client.
class ScopedGLErrorSuppressor {
public:
explicit ScopedGLErrorSuppressor(
const char* function_name, ErrorState* error_state);
~ScopedGLErrorSuppressor();
private:
const char* function_name_;
ErrorState* error_state_;
DISALLOW_COPY_AND_ASSIGN(ScopedGLErrorSuppressor);
};
// Temporarily changes a decoder's bound texture and restore it when this
// object goes out of scope. Also temporarily switches to using active texture
// unit zero in case the client has changed that to something invalid.
class ScopedTextureBinder {
public:
explicit ScopedTextureBinder(ContextState* state, GLuint id, GLenum target);
~ScopedTextureBinder();
private:
ContextState* state_;
GLenum target_;
DISALLOW_COPY_AND_ASSIGN(ScopedTextureBinder);
};
// Temporarily changes a decoder's bound render buffer and restore it when this
// object goes out of scope.
class ScopedRenderBufferBinder {
public:
explicit ScopedRenderBufferBinder(ContextState* state, GLuint id);
~ScopedRenderBufferBinder();
private:
ContextState* state_;
DISALLOW_COPY_AND_ASSIGN(ScopedRenderBufferBinder);
};
// Temporarily changes a decoder's bound frame buffer and restore it when this
// object goes out of scope.
class ScopedFrameBufferBinder {
public:
explicit ScopedFrameBufferBinder(GLES2DecoderImpl* decoder, GLuint id);
~ScopedFrameBufferBinder();
private:
GLES2DecoderImpl* decoder_;
DISALLOW_COPY_AND_ASSIGN(ScopedFrameBufferBinder);
};
// Temporarily changes a decoder's bound frame buffer to a resolved version of
// the multisampled offscreen render buffer if that buffer is multisampled, and,
// if it is bound or enforce_internal_framebuffer is true. If internal is
// true, the resolved framebuffer is not visible to the parent.
class ScopedResolvedFrameBufferBinder {
public:
explicit ScopedResolvedFrameBufferBinder(GLES2DecoderImpl* decoder,
bool enforce_internal_framebuffer,
bool internal);
~ScopedResolvedFrameBufferBinder();
private:
GLES2DecoderImpl* decoder_;
bool resolve_and_bind_;
DISALLOW_COPY_AND_ASSIGN(ScopedResolvedFrameBufferBinder);
};
class ScopedModifyPixels {
public:
explicit ScopedModifyPixels(TextureRef* ref);
~ScopedModifyPixels();
private:
TextureRef* ref_;
};
ScopedModifyPixels::ScopedModifyPixels(TextureRef* ref) : ref_(ref) {
if (ref_)
ref_->texture()->OnWillModifyPixels();
}
ScopedModifyPixels::~ScopedModifyPixels() {
if (ref_)
ref_->texture()->OnDidModifyPixels();
}
class ScopedRenderTo {
public:
explicit ScopedRenderTo(Framebuffer* framebuffer);
~ScopedRenderTo();
private:
const Framebuffer* framebuffer_;
};
ScopedRenderTo::ScopedRenderTo(Framebuffer* framebuffer)
: framebuffer_(framebuffer) {
if (framebuffer)
framebuffer_->OnWillRenderTo();
}
ScopedRenderTo::~ScopedRenderTo() {
if (framebuffer_)
framebuffer_->OnDidRenderTo();
}
// Encapsulates an OpenGL texture.
class BackTexture {
public:
explicit BackTexture(MemoryTracker* memory_tracker, ContextState* state);
~BackTexture();
// Create a new render texture.
void Create();
// Set the initial size and format of a render texture or resize it.
bool AllocateStorage(const gfx::Size& size, GLenum format, bool zero);
// Copy the contents of the currently bound frame buffer.
void Copy(const gfx::Size& size, GLenum format);
// Destroy the render texture. This must be explicitly called before
// destroying this object.
void Destroy();
// Invalidate the texture. This can be used when a context is lost and it is
// not possible to make it current in order to free the resource.
void Invalidate();
GLuint id() const {
return id_;
}
gfx::Size size() const {
return size_;
}
private:
MemoryTypeTracker memory_tracker_;
ContextState* state_;
size_t bytes_allocated_;
GLuint id_;
gfx::Size size_;
DISALLOW_COPY_AND_ASSIGN(BackTexture);
};
// Encapsulates an OpenGL render buffer of any format.
class BackRenderbuffer {
public:
explicit BackRenderbuffer(
RenderbufferManager* renderbuffer_manager,
MemoryTracker* memory_tracker,
ContextState* state);
~BackRenderbuffer();
// Create a new render buffer.
void Create();
// Set the initial size and format of a render buffer or resize it.
bool AllocateStorage(const FeatureInfo* feature_info,
const gfx::Size& size,
GLenum format,
GLsizei samples);
// Destroy the render buffer. This must be explicitly called before destroying
// this object.
void Destroy();
// Invalidate the render buffer. This can be used when a context is lost and
// it is not possible to make it current in order to free the resource.
void Invalidate();
GLuint id() const {
return id_;
}
private:
RenderbufferManager* renderbuffer_manager_;
MemoryTypeTracker memory_tracker_;
ContextState* state_;
size_t bytes_allocated_;
GLuint id_;
DISALLOW_COPY_AND_ASSIGN(BackRenderbuffer);
};
// Encapsulates an OpenGL frame buffer.
class BackFramebuffer {
public:
explicit BackFramebuffer(GLES2DecoderImpl* decoder);
~BackFramebuffer();
// Create a new frame buffer.
void Create();
// Attach a color render buffer to a frame buffer.
void AttachRenderTexture(BackTexture* texture);
// Attach a render buffer to a frame buffer. Note that this unbinds any
// currently bound frame buffer.
void AttachRenderBuffer(GLenum target, BackRenderbuffer* render_buffer);
// Destroy the frame buffer. This must be explicitly called before destroying
// this object.
void Destroy();
// Invalidate the frame buffer. This can be used when a context is lost and it
// is not possible to make it current in order to free the resource.
void Invalidate();
// See glCheckFramebufferStatusEXT.
GLenum CheckStatus();
GLuint id() const {
return id_;
}
private:
GLES2DecoderImpl* decoder_;
GLuint id_;
DISALLOW_COPY_AND_ASSIGN(BackFramebuffer);
};
struct FenceCallback {
explicit FenceCallback()
: fence(gfx::GLFence::Create()) {
DCHECK(fence);
}
std::vector<base::Closure> callbacks;
scoped_ptr<gfx::GLFence> fence;
};
class AsyncUploadTokenCompletionObserver
: public AsyncPixelTransferCompletionObserver {
public:
explicit AsyncUploadTokenCompletionObserver(uint32 async_upload_token)
: async_upload_token_(async_upload_token) {
}
void DidComplete(const AsyncMemoryParams& mem_params) override {
DCHECK(mem_params.buffer().get());
void* data = mem_params.GetDataAddress();
AsyncUploadSync* sync = static_cast<AsyncUploadSync*>(data);
sync->SetAsyncUploadToken(async_upload_token_);
}
private:
~AsyncUploadTokenCompletionObserver() override {}
uint32 async_upload_token_;
DISALLOW_COPY_AND_ASSIGN(AsyncUploadTokenCompletionObserver);
};
// } // anonymous namespace.
// static
const unsigned int GLES2Decoder::kDefaultStencilMask =
static_cast<unsigned int>(-1);
bool GLES2Decoder::GetServiceTextureId(uint32 client_texture_id,
uint32* service_texture_id) {
return false;
}
GLES2Decoder::GLES2Decoder()
: initialized_(false),
debug_(false),
log_commands_(false),
unsafe_es3_apis_enabled_(false) {
}
GLES2Decoder::~GLES2Decoder() {
}
void GLES2Decoder::BeginDecoding() {}
void GLES2Decoder::EndDecoding() {}
// This class implements GLES2Decoder so we don't have to expose all the GLES2
// cmd stuff to outside this class.
class GLES2DecoderImpl : public GLES2Decoder,
public FramebufferManager::TextureDetachObserver,
public ErrorStateClient {
public:
explicit GLES2DecoderImpl(ContextGroup* group);
~GLES2DecoderImpl() override;
// Overridden from AsyncAPIInterface.
Error DoCommand(unsigned int command,
unsigned int arg_count,
const void* args) override;
error::Error DoCommands(unsigned int num_commands,
const void* buffer,
int num_entries,
int* entries_processed) override;
template <bool DebugImpl>
error::Error DoCommandsImpl(unsigned int num_commands,
const void* buffer,
int num_entries,
int* entries_processed);
// Overridden from AsyncAPIInterface.
const char* GetCommandName(unsigned int command_id) const override;
// Overridden from GLES2Decoder.
bool Initialize(const scoped_refptr<gfx::GLSurface>& surface,
const scoped_refptr<gfx::GLContext>& context,
bool offscreen,
const gfx::Size& size,
const DisallowedFeatures& disallowed_features,
const std::vector<int32>& attribs) override;
void Destroy(bool have_context) override;
void SetSurface(const scoped_refptr<gfx::GLSurface>& surface) override;
void ProduceFrontBuffer(const Mailbox& mailbox) override;
bool ResizeOffscreenFrameBuffer(const gfx::Size& size) override;
void UpdateParentTextureInfo();
bool MakeCurrent() override;
GLES2Util* GetGLES2Util() override { return &util_; }
gfx::GLContext* GetGLContext() override { return context_.get(); }
ContextGroup* GetContextGroup() override { return group_.get(); }
Capabilities GetCapabilities() override;
void RestoreState(const ContextState* prev_state) override;
void RestoreActiveTexture() const override { state_.RestoreActiveTexture(); }
void RestoreAllTextureUnitBindings(
const ContextState* prev_state) const override {
state_.RestoreAllTextureUnitBindings(prev_state);
}
void RestoreActiveTextureUnitBinding(unsigned int target) const override {
state_.RestoreActiveTextureUnitBinding(target);
}
void RestoreBufferBindings() const override {
state_.RestoreBufferBindings();
}
void RestoreGlobalState() const override { state_.RestoreGlobalState(NULL); }
void RestoreProgramBindings() const override {
state_.RestoreProgramBindings();
}
void RestoreTextureUnitBindings(unsigned unit) const override {
state_.RestoreTextureUnitBindings(unit, NULL);
}
void RestoreFramebufferBindings() const override;
void RestoreRenderbufferBindings() override;
void RestoreTextureState(unsigned service_id) const override;
void ClearAllAttributes() const override;
void RestoreAllAttributes() const override;
QueryManager* GetQueryManager() override { return query_manager_.get(); }
VertexArrayManager* GetVertexArrayManager() override {
return vertex_array_manager_.get();
}
ImageManager* GetImageManager() override { return image_manager_.get(); }
ValuebufferManager* GetValuebufferManager() override {
return valuebuffer_manager();
}
bool ProcessPendingQueries(bool did_finish) override;
bool HasMoreIdleWork() override;
void PerformIdleWork() override;
void WaitForReadPixels(base::Closure callback) override;
void SetResizeCallback(
const base::Callback<void(gfx::Size, float)>& callback) override;
Logger* GetLogger() override;
void BeginDecoding() override;
void EndDecoding() override;
ErrorState* GetErrorState() override;
const ContextState* GetContextState() override { return &state_; }
void SetShaderCacheCallback(const ShaderCacheCallback& callback) override;
void SetWaitSyncPointCallback(const WaitSyncPointCallback& callback) override;
AsyncPixelTransferManager* GetAsyncPixelTransferManager() override;
void ResetAsyncPixelTransferManagerForTest() override;
void SetAsyncPixelTransferManagerForTest(
AsyncPixelTransferManager* manager) override;
void SetIgnoreCachedStateForTest(bool ignore) override;
void ProcessFinishedAsyncTransfers();
bool GetServiceTextureId(uint32 client_texture_id,
uint32* service_texture_id) override;
uint32 GetTextureUploadCount() override;
base::TimeDelta GetTotalTextureUploadTime() override;
base::TimeDelta GetTotalProcessingCommandsTime() override;
void AddProcessingCommandsTime(base::TimeDelta) override;
// Restores the current state to the user's settings.
void RestoreCurrentFramebufferBindings();
// Sets DEPTH_TEST, STENCIL_TEST and color mask for the current framebuffer.
void ApplyDirtyState();
// These check the state of the currently bound framebuffer or the
// backbuffer if no framebuffer is bound.
// If all_draw_buffers is false, only check with COLOR_ATTACHMENT0, otherwise
// check with all attached and enabled color attachments.
bool BoundFramebufferHasColorAttachmentWithAlpha(bool all_draw_buffers);
bool BoundFramebufferHasDepthAttachment();
bool BoundFramebufferHasStencilAttachment();
error::ContextLostReason GetContextLostReason() override;
// Overridden from FramebufferManager::TextureDetachObserver:
void OnTextureRefDetachedFromFramebuffer(TextureRef* texture) override;
// Overriden from ErrorStateClient.
void OnContextLostError() override;
void OnOutOfMemoryError() override;
// Ensure Renderbuffer corresponding to last DoBindRenderbuffer() is bound.
void EnsureRenderbufferBound();
// Helpers to facilitate calling into compatible extensions.
static void RenderbufferStorageMultisampleHelper(
const FeatureInfo* feature_info,
GLenum target,
GLsizei samples,
GLenum internal_format,
GLsizei width,
GLsizei height);
void BlitFramebufferHelper(GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
private:
friend class ScopedFrameBufferBinder;
friend class ScopedResolvedFrameBufferBinder;
friend class BackFramebuffer;
// Initialize or re-initialize the shader translator.
bool InitializeShaderTranslator();
void UpdateCapabilities();
// Helpers for the glGen and glDelete functions.
bool GenTexturesHelper(GLsizei n, const GLuint* client_ids);
void DeleteTexturesHelper(GLsizei n, const GLuint* client_ids);
bool GenBuffersHelper(GLsizei n, const GLuint* client_ids);
void DeleteBuffersHelper(GLsizei n, const GLuint* client_ids);
bool GenFramebuffersHelper(GLsizei n, const GLuint* client_ids);
void DeleteFramebuffersHelper(GLsizei n, const GLuint* client_ids);
bool GenRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
void DeleteRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
bool GenValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* client_ids);
void DeleteValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* client_ids);
bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
void DeleteQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
bool GenVertexArraysOESHelper(GLsizei n, const GLuint* client_ids);
void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* client_ids);
// Helper for async upload token completion notification callback.
base::Closure AsyncUploadTokenCompletionClosure(uint32 async_upload_token,
uint32 sync_data_shm_id,
uint32 sync_data_shm_offset);
// Workarounds
void OnFboChanged() const;
void OnUseFramebuffer() const;
// TODO(gman): Cache these pointers?
BufferManager* buffer_manager() {
return group_->buffer_manager();
}
RenderbufferManager* renderbuffer_manager() {
return group_->renderbuffer_manager();
}
FramebufferManager* framebuffer_manager() {
return group_->framebuffer_manager();
}
ValuebufferManager* valuebuffer_manager() {
return group_->valuebuffer_manager();
}
ProgramManager* program_manager() {
return group_->program_manager();
}
ShaderManager* shader_manager() {
return group_->shader_manager();
}
ShaderTranslatorCache* shader_translator_cache() {
return group_->shader_translator_cache();
}
const TextureManager* texture_manager() const {
return group_->texture_manager();
}
TextureManager* texture_manager() {
return group_->texture_manager();
}
MailboxManager* mailbox_manager() {
return group_->mailbox_manager();
}
ImageManager* image_manager() { return image_manager_.get(); }
VertexArrayManager* vertex_array_manager() {
return vertex_array_manager_.get();
}
MemoryTracker* memory_tracker() {
return group_->memory_tracker();
}
bool EnsureGPUMemoryAvailable(size_t estimated_size) {
MemoryTracker* tracker = memory_tracker();
if (tracker) {
return tracker->EnsureGPUMemoryAvailable(estimated_size);
}
return true;
}
bool IsOffscreenBufferMultisampled() const {
return offscreen_target_samples_ > 1;
}
// Creates a Texture for the given texture.
TextureRef* CreateTexture(
GLuint client_id, GLuint service_id) {
return texture_manager()->CreateTexture(client_id, service_id);
}
// Gets the texture info for the given texture. Returns NULL if none exists.
TextureRef* GetTexture(GLuint client_id) const {
return texture_manager()->GetTexture(client_id);
}
// Deletes the texture info for the given texture.
void RemoveTexture(GLuint client_id) {
texture_manager()->RemoveTexture(client_id);
}
// Get the size (in pixels) of the currently bound frame buffer (either FBO
// or regular back buffer).
gfx::Size GetBoundReadFrameBufferSize();
// Get the format of the currently bound frame buffer (either FBO or regular
// back buffer)
GLenum GetBoundReadFrameBufferTextureType();
GLenum GetBoundReadFrameBufferInternalFormat();
GLenum GetBoundDrawFrameBufferInternalFormat();
// Wrapper for CompressedTexImage2D commands.
error::Error DoCompressedTexImage2D(
GLenum target,
GLint level,
GLenum internal_format,
GLsizei width,
GLsizei height,
GLint border,
GLsizei image_size,
const void* data);
// Wrapper for CompressedTexSubImage2D.
void DoCompressedTexSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLsizei imageSize,
const void * data);
// Wrapper for CopyTexImage2D.
void DoCopyTexImage2D(
GLenum target,
GLint level,
GLenum internal_format,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border);
// Wrapper for SwapBuffers.
void DoSwapBuffers();
// Wrapper for SwapInterval.
void DoSwapInterval(int interval);
// Wrapper for CopyTexSubImage2D.
void DoCopyTexSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height);
// Validation for TexSubImage2D.
bool ValidateTexSubImage2D(
error::Error* error,
const char* function_name,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
const void * data);
// Wrapper for TexSubImage2D.
error::Error DoTexSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
const void * data);
// Extra validation for async tex(Sub)Image2D.
bool ValidateAsyncTransfer(
const char* function_name,
TextureRef* texture_ref,
GLenum target,
GLint level,
const void * data);
// Wrapper for TexImageIOSurface2DCHROMIUM.
void DoTexImageIOSurface2DCHROMIUM(
GLenum target,
GLsizei width,
GLsizei height,
GLuint io_surface_id,
GLuint plane);
void DoCopyTextureCHROMIUM(
GLenum target,
GLuint source_id,
GLuint target_id,
GLint level,
GLenum internal_format,
GLenum dest_type);
// Wrapper for TexStorage2DEXT.
void DoTexStorage2DEXT(
GLenum target,
GLint levels,
GLenum internal_format,
GLsizei width,
GLsizei height);
void DoProduceTextureCHROMIUM(GLenum target, const GLbyte* key);
void DoProduceTextureDirectCHROMIUM(GLuint texture, GLenum target,
const GLbyte* key);
void ProduceTextureRef(std::string func_name, TextureRef* texture_ref,
GLenum target, const GLbyte* data);
void DoConsumeTextureCHROMIUM(GLenum target, const GLbyte* key);
void DoCreateAndConsumeTextureCHROMIUM(GLenum target, const GLbyte* key,
GLuint client_id);
bool DoIsValuebufferCHROMIUM(GLuint client_id);
void DoBindValueBufferCHROMIUM(GLenum target, GLuint valuebuffer);
void DoSubscribeValueCHROMIUM(GLenum target, GLenum subscription);
void DoPopulateSubscribedValuesCHROMIUM(GLenum target);
void DoUniformValueBufferCHROMIUM(GLint location,
GLenum target,
GLenum subscription);
void DoBindTexImage2DCHROMIUM(
GLenum target,
GLint image_id);
void DoReleaseTexImage2DCHROMIUM(
GLenum target,
GLint image_id);
void DoTraceEndCHROMIUM(void);
void DoDrawBuffersEXT(GLsizei count, const GLenum* bufs);
void DoLoseContextCHROMIUM(GLenum current, GLenum other);
void DoMatrixLoadfCHROMIUM(GLenum matrix_mode, const GLfloat* matrix);
void DoMatrixLoadIdentityCHROMIUM(GLenum matrix_mode);
// Creates a Program for the given program.
Program* CreateProgram(
GLuint client_id, GLuint service_id) {
return program_manager()->CreateProgram(client_id, service_id);
}
// Gets the program info for the given program. Returns NULL if none exists.
Program* GetProgram(GLuint client_id) {
return program_manager()->GetProgram(client_id);
}
#if defined(NDEBUG)
void LogClientServiceMapping(
const char* /* function_name */,
GLuint /* client_id */,
GLuint /* service_id */) {
}
template<typename T>
void LogClientServiceForInfo(
T* /* info */, GLuint /* client_id */, const char* /* function_name */) {
}
#else
void LogClientServiceMapping(
const char* function_name, GLuint client_id, GLuint service_id) {
if (service_logging_) {
VLOG(1) << "[" << logger_.GetLogPrefix() << "] " << function_name
<< ": client_id = " << client_id
<< ", service_id = " << service_id;
}
}
template<typename T>
void LogClientServiceForInfo(
T* info, GLuint client_id, const char* function_name) {
if (info) {
LogClientServiceMapping(function_name, client_id, info->service_id());
}
}
#endif
// Gets the program info for the given program. If it's not a program
// generates a GL error. Returns NULL if not program.
Program* GetProgramInfoNotShader(
GLuint client_id, const char* function_name) {
Program* program = GetProgram(client_id);
if (!program) {
if (GetShader(client_id)) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, function_name, "shader passed for program");
} else {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "unknown program");
}
}
LogClientServiceForInfo(program, client_id, function_name);
return program;
}
// Creates a Shader for the given shader.
Shader* CreateShader(
GLuint client_id,
GLuint service_id,
GLenum shader_type) {
return shader_manager()->CreateShader(
client_id, service_id, shader_type);
}
// Gets the shader info for the given shader. Returns NULL if none exists.
Shader* GetShader(GLuint client_id) {
return shader_manager()->GetShader(client_id);
}
// Gets the shader info for the given shader. If it's not a shader generates a
// GL error. Returns NULL if not shader.
Shader* GetShaderInfoNotProgram(
GLuint client_id, const char* function_name) {
Shader* shader = GetShader(client_id);
if (!shader) {
if (GetProgram(client_id)) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, function_name, "program passed for shader");
} else {
LOCAL_SET_GL_ERROR(
GL_INVALID_VALUE, function_name, "unknown shader");
}
}
LogClientServiceForInfo(shader, client_id, function_name);
return shader;
}
// Creates a buffer info for the given buffer.
void CreateBuffer(GLuint client_id, GLuint service_id) {
return buffer_manager()->CreateBuffer(client_id, service_id);
}
// Gets the buffer info for the given buffer.
Buffer* GetBuffer(GLuint client_id) {
Buffer* buffer = buffer_manager()->GetBuffer(client_id);
return buffer;
}
// Removes any buffers in the VertexAtrribInfos and BufferInfos. This is used
// on glDeleteBuffers so we can make sure the user does not try to render
// with deleted buffers.
void RemoveBuffer(GLuint client_id);
// Creates a framebuffer info for the given framebuffer.
void CreateFramebuffer(GLuint client_id, GLuint service_id) {
return framebuffer_manager()->CreateFramebuffer(client_id, service_id);
}
// Gets the framebuffer info for the given framebuffer.
Framebuffer* GetFramebuffer(GLuint client_id) {
return framebuffer_manager()->GetFramebuffer(client_id);
}
// Removes the framebuffer info for the given framebuffer.
void RemoveFramebuffer(GLuint client_id) {
framebuffer_manager()->RemoveFramebuffer(client_id);
}
// Creates a renderbuffer info for the given renderbuffer.
void CreateRenderbuffer(GLuint client_id, GLuint service_id) {
return renderbuffer_manager()->CreateRenderbuffer(
client_id, service_id);
}
// Gets the renderbuffer info for the given renderbuffer.
Renderbuffer* GetRenderbuffer(GLuint client_id) {
return renderbuffer_manager()->GetRenderbuffer(client_id);
}
// Removes the renderbuffer info for the given renderbuffer.
void RemoveRenderbuffer(GLuint client_id) {
renderbuffer_manager()->RemoveRenderbuffer(client_id);
}
// Creates a valuebuffer info for the given valuebuffer.
void CreateValuebuffer(GLuint client_id) {
return valuebuffer_manager()->CreateValuebuffer(client_id);
}
// Gets the valuebuffer info for a given valuebuffer.
Valuebuffer* GetValuebuffer(GLuint client_id) {
return valuebuffer_manager()->GetValuebuffer(client_id);
}
// Removes the valuebuffer info for the given valuebuffer.
void RemoveValuebuffer(GLuint client_id) {
valuebuffer_manager()->RemoveValuebuffer(client_id);
}
// Gets the vertex attrib manager for the given vertex array.
VertexAttribManager* GetVertexAttribManager(GLuint client_id) {
VertexAttribManager* info =
vertex_array_manager()->GetVertexAttribManager(client_id);
return info;
}
// Removes the vertex attrib manager for the given vertex array.
void RemoveVertexAttribManager(GLuint client_id) {
vertex_array_manager()->RemoveVertexAttribManager(client_id);
}
// Creates a vertex attrib manager for the given vertex array.
scoped_refptr<VertexAttribManager> CreateVertexAttribManager(
GLuint client_id,
GLuint service_id,
bool client_visible) {
return vertex_array_manager()->CreateVertexAttribManager(
client_id, service_id, group_->max_vertex_attribs(), client_visible);
}
void DoBindAttribLocation(GLuint client_id, GLuint index, const char* name);
void DoBindUniformLocationCHROMIUM(
GLuint client_id, GLint location, const char* name);
error::Error GetAttribLocationHelper(
GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
const std::string& name_str);
error::Error GetUniformLocationHelper(
GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
const std::string& name_str);
error::Error GetFragDataLocationHelper(
GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
const std::string& name_str);
// Wrapper for glShaderSource.
void DoShaderSource(
GLuint client_id, GLsizei count, const char** data, const GLint* length);
// Wrapper for glTransformFeedbackVaryings.
void DoTransformFeedbackVaryings(
GLuint client_program_id, GLsizei count, const char* const* varyings,
GLenum buffer_mode);
// Clear any textures used by the current program.
bool ClearUnclearedTextures();
// Clears any uncleared attachments attached to the given frame buffer.
// Returns false if there was a generated GL error.
void ClearUnclearedAttachments(GLenum target, Framebuffer* framebuffer);
// overridden from GLES2Decoder
bool ClearLevel(Texture* texture,
unsigned target,
int level,
unsigned internal_format,
unsigned format,
unsigned type,
int width,
int height,
bool is_texture_immutable) override;
// Restore all GL state that affects clearing.
void RestoreClearState();
// Remembers the state of some capabilities.
// Returns: true if glEnable/glDisable should actually be called.
bool SetCapabilityState(GLenum cap, bool enabled);
// Check that the currently bound framebuffers are valid.
// Generates GL error if not.
bool CheckBoundFramebuffersValid(const char* func_name);
// Check that the currently bound read framebuffer has a color image
// attached. Generates GL error if not.
bool CheckBoundReadFramebufferColorAttachment(const char* func_name);
// Check that the currently bound read framebuffer's color image
// isn't the target texture of the glCopyTex{Sub}Image2D.
bool FormsTextureCopyingFeedbackLoop(TextureRef* texture, GLint level);
// Check if a framebuffer meets our requirements.
bool CheckFramebufferValid(
Framebuffer* framebuffer,
GLenum target,
const char* func_name);
// Check if the current valuebuffer exists and is valid. If not generates
// the appropriate GL error. Returns true if the current valuebuffer is in
// a usable state.
bool CheckCurrentValuebuffer(const char* function_name);
// Check if the current valuebuffer exists and is valiud and that the
// value buffer is actually subscribed to the given subscription
bool CheckCurrentValuebufferForSubscription(GLenum subscription,
const char* function_name);
// Check if the location can be used for the given subscription target. If not
// generates the appropriate GL error. Returns true if the location is usable
bool CheckSubscriptionTarget(GLint location,
GLenum subscription,
const char* function_name);
// Checks if the current program exists and is valid. If not generates the
// appropriate GL error. Returns true if the current program is in a usable
// state.
bool CheckCurrentProgram(const char* function_name);
// Checks if the current program exists and is valid and that location is not
// -1. If the current program is not valid generates the appropriate GL
// error. Returns true if the current program is in a usable state and
// location is not -1.
bool CheckCurrentProgramForUniform(GLint location, const char* function_name);
// Checks if the current program samples a texture that is also the color
// image of the current bound framebuffer, i.e., the source and destination
// of the draw operation are the same.
bool CheckDrawingFeedbackLoops();
// Checks if |api_type| is valid for the given uniform
// If the api type is not valid generates the appropriate GL
// error. Returns true if |api_type| is valid for the uniform
bool CheckUniformForApiType(const Program::UniformInfo* info,
const char* function_name,
Program::UniformApiType api_type);
// Gets the type of a uniform for a location in the current program. Sets GL
// errors if the current program is not valid. Returns true if the current
// program is valid and the location exists. Adjusts count so it
// does not overflow the uniform.
bool PrepForSetUniformByLocation(GLint fake_location,
const char* function_name,
Program::UniformApiType api_type,
GLint* real_location,
GLenum* type,
GLsizei* count);
// Gets the service id for any simulated backbuffer fbo.
GLuint GetBackbufferServiceId() const;
// Helper for glGetBooleanv, glGetFloatv and glGetIntegerv
bool GetHelper(GLenum pname, GLint* params, GLsizei* num_written);
// Helper for glGetVertexAttrib
void GetVertexAttribHelper(
const VertexAttrib* attrib, GLenum pname, GLint* param);
// Wrapper for glActiveTexture
void DoActiveTexture(GLenum texture_unit);
// Wrapper for glAttachShader
void DoAttachShader(GLuint client_program_id, GLint client_shader_id);
// Wrapper for glBindBuffer since we need to track the current targets.
void DoBindBuffer(GLenum target, GLuint buffer);
// Wrapper for glBindFramebuffer since we need to track the current targets.
void DoBindFramebuffer(GLenum target, GLuint framebuffer);
// Wrapper for glBindRenderbuffer since we need to track the current targets.
void DoBindRenderbuffer(GLenum target, GLuint renderbuffer);
// Wrapper for glBindTexture since we need to track the current targets.
void DoBindTexture(GLenum target, GLuint texture);
// Wrapper for glBindVertexArrayOES
void DoBindVertexArrayOES(GLuint array);
void EmulateVertexArrayState();
// Wrapper for glBlitFramebufferCHROMIUM.
void DoBlitFramebufferCHROMIUM(
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
// Wrapper for glBufferSubData.
void DoBufferSubData(
GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);
// Wrapper for glCheckFramebufferStatus
GLenum DoCheckFramebufferStatus(GLenum target);
// Wrapper for glClear
error::Error DoClear(GLbitfield mask);
// Wrappers for various state.
void DoDepthRangef(GLclampf znear, GLclampf zfar);
void DoSampleCoverage(GLclampf value, GLboolean invert);
// Wrapper for glCompileShader.
void DoCompileShader(GLuint shader);
// Wrapper for glDetachShader
void DoDetachShader(GLuint client_program_id, GLint client_shader_id);
// Wrapper for glDisable
void DoDisable(GLenum cap);
// Wrapper for glDisableVertexAttribArray.
void DoDisableVertexAttribArray(GLuint index);
// Wrapper for glDiscardFramebufferEXT, since we need to track undefined
// attachments.
void DoDiscardFramebufferEXT(GLenum target,
GLsizei numAttachments,
const GLenum* attachments);
// Wrapper for glEnable
void DoEnable(GLenum cap);
// Wrapper for glEnableVertexAttribArray.
void DoEnableVertexAttribArray(GLuint index);
// Wrapper for glFinish.
void DoFinish();
// Wrapper for glFlush.
void DoFlush();
// Wrapper for glFramebufferRenderbufffer.
void DoFramebufferRenderbuffer(
GLenum target, GLenum attachment, GLenum renderbuffertarget,
GLuint renderbuffer);
// Wrapper for glFramebufferTexture2D.
void DoFramebufferTexture2D(
GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
GLint level);
// Wrapper for glFramebufferTexture2DMultisampleEXT.
void DoFramebufferTexture2DMultisample(
GLenum target, GLenum attachment, GLenum textarget,
GLuint texture, GLint level, GLsizei samples);
// Common implementation for both DoFramebufferTexture2D wrappers.
void DoFramebufferTexture2DCommon(const char* name,
GLenum target, GLenum attachment, GLenum textarget,
GLuint texture, GLint level, GLsizei samples);
// Wrapper for glFramebufferTextureLayer.
void DoFramebufferTextureLayer(
GLenum target, GLenum attachment, GLuint texture, GLint level,
GLint layer);
// Wrapper for glGenerateMipmap
void DoGenerateMipmap(GLenum target);
// Helper for DoGetBooleanv, Floatv, and Intergerv to adjust pname
// to account for different pname values defined in different extension
// variants.
GLenum AdjustGetPname(GLenum pname);
// Wrapper for DoGetBooleanv.
void DoGetBooleanv(GLenum pname, GLboolean* params);
// Wrapper for DoGetFloatv.
void DoGetFloatv(GLenum pname, GLfloat* params);
// Wrapper for glGetFramebufferAttachmentParameteriv.
void DoGetFramebufferAttachmentParameteriv(
GLenum target, GLenum attachment, GLenum pname, GLint* params);
// Wrapper for glGetIntegerv.
void DoGetIntegerv(GLenum pname, GLint* params);
// Gets the max value in a range in a buffer.
GLuint DoGetMaxValueInBufferCHROMIUM(
GLuint buffer_id, GLsizei count, GLenum type, GLuint offset);
// Wrapper for glGetBufferParameteriv.
void DoGetBufferParameteriv(
GLenum target, GLenum pname, GLint* params);
// Wrapper for glGetProgramiv.
void DoGetProgramiv(
GLuint program_id, GLenum pname, GLint* params);
// Wrapper for glRenderbufferParameteriv.
void DoGetRenderbufferParameteriv(
GLenum target, GLenum pname, GLint* params);
// Wrapper for glGetShaderiv
void DoGetShaderiv(GLuint shader, GLenum pname, GLint* params);
// Wrappers for glGetTexParameter.
void DoGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
void DoGetTexParameteriv(GLenum target, GLenum pname, GLint* params);
void InitTextureMaxAnisotropyIfNeeded(GLenum target, GLenum pname);
// Wrappers for glGetVertexAttrib.
void DoGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params);
void DoGetVertexAttribiv(GLuint index, GLenum pname, GLint *params);
// Wrappers for glIsXXX functions.
bool DoIsEnabled(GLenum cap);
bool DoIsBuffer(GLuint client_id);
bool DoIsFramebuffer(GLuint client_id);
bool DoIsProgram(GLuint client_id);
bool DoIsRenderbuffer(GLuint client_id);
bool DoIsShader(GLuint client_id);
bool DoIsTexture(GLuint client_id);
bool DoIsVertexArrayOES(GLuint client_id);
// Wrapper for glLinkProgram
void DoLinkProgram(GLuint program);
// Wrapper for glRenderbufferStorage.
void DoRenderbufferStorage(
GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
// Handler for glRenderbufferStorageMultisampleCHROMIUM.
void DoRenderbufferStorageMultisampleCHROMIUM(
GLenum target, GLsizei samples, GLenum internalformat,
GLsizei width, GLsizei height);
// Handler for glRenderbufferStorageMultisampleEXT
// (multisampled_render_to_texture).
void DoRenderbufferStorageMultisampleEXT(
GLenum target, GLsizei samples, GLenum internalformat,
GLsizei width, GLsizei height);
// Common validation for multisample extensions.
bool ValidateRenderbufferStorageMultisample(GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height);
// Verifies that the currently bound multisample renderbuffer is valid
// Very slow! Only done on platforms with driver bugs that return invalid
// buffers under memory pressure
bool VerifyMultisampleRenderbufferIntegrity(
GLuint renderbuffer, GLenum format);
// Wrapper for glReleaseShaderCompiler.
void DoReleaseShaderCompiler() { }
// Wrappers for glSamplerParameter*v functions.
void DoSamplerParameterfv(
GLuint sampler, GLenum pname, const GLfloat* params);
void DoSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* params);
// Wrappers for glTexParameter functions.
void DoTexParameterf(GLenum target, GLenum pname, GLfloat param);
void DoTexParameteri(GLenum target, GLenum pname, GLint param);
void DoTexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
void DoTexParameteriv(GLenum target, GLenum pname, const GLint* params);
// Wrappers for glUniform1i and glUniform1iv as according to the GLES2
// spec only these 2 functions can be used to set sampler uniforms.
void DoUniform1i(GLint fake_location, GLint v0);
void DoUniform1iv(GLint fake_location, GLsizei count, const GLint* value);
void DoUniform2iv(GLint fake_location, GLsizei count, const GLint* value);
void DoUniform3iv(GLint fake_location, GLsizei count, const GLint* value);
void DoUniform4iv(GLint fake_location, GLsizei count, const GLint* value);
// Wrappers for glUniformfv because some drivers don't correctly accept
// bool uniforms.
void DoUniform1fv(GLint fake_location, GLsizei count, const GLfloat* value);
void DoUniform2fv(GLint fake_location, GLsizei count, const GLfloat* value);
void DoUniform3fv(GLint fake_location, GLsizei count, const GLfloat* value);
void DoUniform4fv(GLint fake_location, GLsizei count, const GLfloat* value);
void DoUniformMatrix2fv(
GLint fake_location, GLsizei count, GLboolean transpose,
const GLfloat* value);
void DoUniformMatrix3fv(
GLint fake_location, GLsizei count, GLboolean transpose,
const GLfloat* value);
void DoUniformMatrix4fv(
GLint fake_location, GLsizei count, GLboolean transpose,
const GLfloat* value);
bool SetVertexAttribValue(
const char* function_name, GLuint index, const GLfloat* value);
// Wrappers for glVertexAttrib??
void DoVertexAttrib1f(GLuint index, GLfloat v0);
void DoVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1);
void DoVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2);
void DoVertexAttrib4f(
GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
void DoVertexAttrib1fv(GLuint index, const GLfloat *v);
void DoVertexAttrib2fv(GLuint index, const GLfloat *v);
void DoVertexAttrib3fv(GLuint index, const GLfloat *v);
void DoVertexAttrib4fv(GLuint index, const GLfloat *v);
// Wrapper for glViewport
void DoViewport(GLint x, GLint y, GLsizei width, GLsizei height);
// Wrapper for glUseProgram
void DoUseProgram(GLuint program);
// Wrapper for glValidateProgram.
void DoValidateProgram(GLuint program_client_id);
void DoInsertEventMarkerEXT(GLsizei length, const GLchar* marker);
void DoPushGroupMarkerEXT(GLsizei length, const GLchar* group);
void DoPopGroupMarkerEXT(void);
// Gets the number of values that will be returned by glGetXXX. Returns
// false if pname is unknown.
bool GetNumValuesReturnedForGLGet(GLenum pname, GLsizei* num_values);
// Checks if the current program and vertex attributes are valid for drawing.
bool IsDrawValid(
const char* function_name, GLuint max_vertex_accessed, bool instanced,
GLsizei primcount);
// Returns true if successful, simulated will be true if attrib0 was
// simulated.
bool SimulateAttrib0(
const char* function_name, GLuint max_vertex_accessed, bool* simulated);
void RestoreStateForAttrib(GLuint attrib, bool restore_array_binding);
// If an image is bound to texture, this will call Will/DidUseTexImage
// if needed.
void DoWillUseTexImageIfNeeded(Texture* texture, GLenum textarget);
void DoDidUseTexImageIfNeeded(Texture* texture, GLenum textarget);
// Returns false if textures were replaced.
bool PrepareTexturesForRender();
void RestoreStateForTextures();
// Returns true if GL_FIXED attribs were simulated.
bool SimulateFixedAttribs(
const char* function_name,
GLuint max_vertex_accessed, bool* simulated, GLsizei primcount);
void RestoreStateForSimulatedFixedAttribs();
// Handle DrawArrays and DrawElements for both instanced and non-instanced
// cases (primcount is always 1 for non-instanced).
error::Error DoDrawArrays(
const char* function_name,
bool instanced, GLenum mode, GLint first, GLsizei count,
GLsizei primcount);
error::Error DoDrawElements(
const char* function_name,
bool instanced, GLenum mode, GLsizei count, GLenum type,
int32 offset, GLsizei primcount);
GLenum GetBindTargetForSamplerType(GLenum type) {
DCHECK(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE ||
type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_2D_RECT_ARB);
switch (type) {
case GL_SAMPLER_2D:
return GL_TEXTURE_2D;
case GL_SAMPLER_CUBE:
return GL_TEXTURE_CUBE_MAP;
case GL_SAMPLER_EXTERNAL_OES:
return GL_TEXTURE_EXTERNAL_OES;
case GL_SAMPLER_2D_RECT_ARB:
return GL_TEXTURE_RECTANGLE_ARB;
}
NOTREACHED();
return 0;
}
// Gets the framebuffer info for a particular target.
Framebuffer* GetFramebufferInfoForTarget(GLenum target) {
Framebuffer* framebuffer = NULL;
switch (target) {
case GL_FRAMEBUFFER:
case GL_DRAW_FRAMEBUFFER_EXT:
framebuffer = framebuffer_state_.bound_draw_framebuffer.get();
break;
case GL_READ_FRAMEBUFFER_EXT:
framebuffer = framebuffer_state_.bound_read_framebuffer.get();
break;
default:
NOTREACHED();
break;
}
return framebuffer;
}
Renderbuffer* GetRenderbufferInfoForTarget(
GLenum target) {
Renderbuffer* renderbuffer = NULL;
switch (target) {
case GL_RENDERBUFFER:
renderbuffer = state_.bound_renderbuffer.get();
break;
default:
NOTREACHED();
break;
}
return renderbuffer;
}
// Validates the program and location for a glGetUniform call and returns
// a SizeResult setup to receive the result. Returns true if glGetUniform
// should be called.
bool GetUniformSetup(GLuint program,
GLint fake_location,
uint32 shm_id,
uint32 shm_offset,
error::Error* error,
GLint* real_location,
GLuint* service_id,
void** result,
GLenum* result_type,
GLsizei* result_size);
void MaybeExitOnContextLost();
bool WasContextLost() override;
bool WasContextLostByRobustnessExtension() override;
void LoseContext(uint32 reset_status) override;
#if defined(OS_MACOSX)
void ReleaseIOSurfaceForTexture(GLuint texture_id);
#endif
bool ValidateCompressedTexDimensions(
const char* function_name,
GLint level, GLsizei width, GLsizei height, GLenum format);
bool ValidateCompressedTexFuncData(
const char* function_name,
GLsizei width, GLsizei height, GLenum format, size_t size);
bool ValidateCompressedTexSubDimensions(
const char* function_name,
GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height, GLenum format,
Texture* texture);
void RenderWarning(const char* filename, int line, const std::string& msg);
void PerformanceWarning(
const char* filename, int line, const std::string& msg);
const FeatureInfo::FeatureFlags& features() const {
return feature_info_->feature_flags();
}
const FeatureInfo::Workarounds& workarounds() const {
return feature_info_->workarounds();
}
bool ShouldDeferDraws() {
return !offscreen_target_frame_buffer_.get() &&
framebuffer_state_.bound_draw_framebuffer.get() == NULL &&
surface_->DeferDraws();
}
bool ShouldDeferReads() {
return !offscreen_target_frame_buffer_.get() &&
framebuffer_state_.bound_read_framebuffer.get() == NULL &&
surface_->DeferDraws();
}
bool IsRobustnessSupported() {
return has_robustness_extension_ &&
context_->WasAllocatedUsingRobustnessExtension();
}
error::Error WillAccessBoundFramebufferForDraw() {
if (ShouldDeferDraws())
return error::kDeferCommandUntilLater;
if (!offscreen_target_frame_buffer_.get() &&
!framebuffer_state_.bound_draw_framebuffer.get() &&
!surface_->SetBackbufferAllocation(true))
return error::kLostContext;
return error::kNoError;
}
error::Error WillAccessBoundFramebufferForRead() {
if (ShouldDeferReads())
return error::kDeferCommandUntilLater;
if (!offscreen_target_frame_buffer_.get() &&
!framebuffer_state_.bound_read_framebuffer.get() &&
!surface_->SetBackbufferAllocation(true))
return error::kLostContext;
return error::kNoError;
}
// Set remaining commands to process to 0 to force DoCommands to return
// and allow context preemption and GPU watchdog checks in GpuScheduler().
void ExitCommandProcessingEarly() { commands_to_process_ = 0; }
void ProcessPendingReadPixels();
void FinishReadPixels(const cmds::ReadPixels& c, GLuint buffer);
// Generate a member function prototype for each command in an automated and
// typesafe way.
#define GLES2_CMD_OP(name) \
Error Handle##name(uint32 immediate_data_size, const void* data);
GLES2_COMMAND_LIST(GLES2_CMD_OP)
#undef GLES2_CMD_OP
// The GL context this decoder renders to on behalf of the client.
scoped_refptr<gfx::GLSurface> surface_;
scoped_refptr<gfx::GLContext> context_;
// The ContextGroup for this decoder uses to track resources.
scoped_refptr<ContextGroup> group_;
DebugMarkerManager debug_marker_manager_;
Logger logger_;
// All the state for this context.
ContextState state_;
// Current width and height of the offscreen frame buffer.
gfx::Size offscreen_size_;
// Util to help with GL.
GLES2Util util_;
// unpack flip y as last set by glPixelStorei
bool unpack_flip_y_;
// unpack (un)premultiply alpha as last set by glPixelStorei
bool unpack_premultiply_alpha_;
bool unpack_unpremultiply_alpha_;
// The buffer we bind to attrib 0 since OpenGL requires it (ES does not).
GLuint attrib_0_buffer_id_;
// The value currently in attrib_0.
Vec4 attrib_0_value_;
// Whether or not the attrib_0 buffer holds the attrib_0_value.
bool attrib_0_buffer_matches_value_;
// The size of attrib 0.
GLsizei attrib_0_size_;
// The buffer used to simulate GL_FIXED attribs.
GLuint fixed_attrib_buffer_id_;
// The size of fiixed attrib buffer.
GLsizei fixed_attrib_buffer_size_;
// The offscreen frame buffer that the client renders to. With EGL, the
// depth and stencil buffers are separate. With regular GL there is a single
// packed depth stencil buffer in offscreen_target_depth_render_buffer_.
// offscreen_target_stencil_render_buffer_ is unused.
scoped_ptr<BackFramebuffer> offscreen_target_frame_buffer_;
scoped_ptr<BackTexture> offscreen_target_color_texture_;
scoped_ptr<BackRenderbuffer> offscreen_target_color_render_buffer_;
scoped_ptr<BackRenderbuffer> offscreen_target_depth_render_buffer_;
scoped_ptr<BackRenderbuffer> offscreen_target_stencil_render_buffer_;
GLenum offscreen_target_color_format_;
GLenum offscreen_target_depth_format_;
GLenum offscreen_target_stencil_format_;
GLsizei offscreen_target_samples_;
GLboolean offscreen_target_buffer_preserved_;
// The copy that is saved when SwapBuffers is called.
scoped_ptr<BackFramebuffer> offscreen_saved_frame_buffer_;
scoped_ptr<BackTexture> offscreen_saved_color_texture_;
scoped_refptr<TextureRef>
offscreen_saved_color_texture_info_;
// The copy that is used as the destination for multi-sample resolves.
scoped_ptr<BackFramebuffer> offscreen_resolved_frame_buffer_;
scoped_ptr<BackTexture> offscreen_resolved_color_texture_;
GLenum offscreen_saved_color_format_;
scoped_ptr<QueryManager> query_manager_;
scoped_ptr<VertexArrayManager> vertex_array_manager_;
scoped_ptr<ImageManager> image_manager_;
base::Callback<void(gfx::Size, float)> resize_callback_;
WaitSyncPointCallback wait_sync_point_callback_;
ShaderCacheCallback shader_cache_callback_;
scoped_ptr<AsyncPixelTransferManager> async_pixel_transfer_manager_;
// The format of the back buffer_
GLenum back_buffer_color_format_;
bool back_buffer_has_depth_;
bool back_buffer_has_stencil_;
bool surfaceless_;
// Backbuffer attachments that are currently undefined.
uint32 backbuffer_needs_clear_bits_;
// The current decoder error communicates the decoder error through command
// processing functions that do not return the error value. Should be set only
// if not returning an error.
error::Error current_decoder_error_;
bool use_shader_translator_;
scoped_refptr<ShaderTranslatorInterface> vertex_translator_;
scoped_refptr<ShaderTranslatorInterface> fragment_translator_;
DisallowedFeatures disallowed_features_;
// Cached from ContextGroup
const Validators* validators_;
scoped_refptr<FeatureInfo> feature_info_;
int frame_number_;
// Number of commands remaining to be processed in DoCommands().
int commands_to_process_;
bool has_robustness_extension_;
GLenum reset_status_;
bool reset_by_robustness_extension_;
bool supports_post_sub_buffer_;
// These flags are used to override the state of the shared feature_info_
// member. Because the same FeatureInfo instance may be shared among many
// contexts, the assumptions on the availablity of extensions in WebGL
// contexts may be broken. These flags override the shared state to preserve
// WebGL semantics.
bool force_webgl_glsl_validation_;
bool derivatives_explicitly_enabled_;
bool frag_depth_explicitly_enabled_;
bool draw_buffers_explicitly_enabled_;
bool shader_texture_lod_explicitly_enabled_;
bool compile_shader_always_succeeds_;
// An optional behaviour to lose the context and group when OOM.
bool lose_context_when_out_of_memory_;
// Log extra info.
bool service_logging_;
#if defined(OS_MACOSX)
typedef std::map<GLuint, IOSurfaceRef> TextureToIOSurfaceMap;
TextureToIOSurfaceMap texture_to_io_surface_map_;
#endif
scoped_ptr<CopyTextureCHROMIUMResourceManager> copy_texture_CHROMIUM_;
scoped_ptr<ClearFramebufferResourceManager> clear_framebuffer_blit_;
// Cached values of the currently assigned viewport dimensions.
GLsizei viewport_max_width_;
GLsizei viewport_max_height_;
// Command buffer stats.
base::TimeDelta total_processing_commands_time_;
// States related to each manager.
DecoderTextureState texture_state_;
DecoderFramebufferState framebuffer_state_;
scoped_ptr<GPUTracer> gpu_tracer_;
scoped_ptr<GPUStateTracer> gpu_state_tracer_;
const unsigned char* cb_command_trace_category_;
const unsigned char* gpu_decoder_category_;
int gpu_trace_level_;
bool gpu_trace_commands_;
bool gpu_debug_commands_;
std::queue<linked_ptr<FenceCallback> > pending_readpixel_fences_;
// Used to validate multisample renderbuffers if needed
GLuint validation_texture_;
GLuint validation_fbo_multisample_;
GLuint validation_fbo_;
typedef gpu::gles2::GLES2Decoder::Error (GLES2DecoderImpl::*CmdHandler)(
uint32 immediate_data_size,
const void* data);
// A struct to hold info about each command.
struct CommandInfo {
CmdHandler cmd_handler;
uint8 arg_flags; // How to handle the arguments for this command
uint8 cmd_flags; // How to handle this command
uint16 arg_count; // How many arguments are expected for this command.
};
// A table of CommandInfo for all the commands.
static const CommandInfo command_info[kNumCommands - kStartPoint];
DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
};
const GLES2DecoderImpl::CommandInfo GLES2DecoderImpl::command_info[] = {
#define GLES2_CMD_OP(name) \
{ \
&GLES2DecoderImpl::Handle##name, cmds::name::kArgFlags, \
cmds::name::cmd_flags, \
sizeof(cmds::name) / sizeof(CommandBufferEntry) - 1, \
} \
, /* NOLINT */
GLES2_COMMAND_LIST(GLES2_CMD_OP)
#undef GLES2_CMD_OP
};
ScopedGLErrorSuppressor::ScopedGLErrorSuppressor(
const char* function_name, ErrorState* error_state)
: function_name_(function_name),
error_state_(error_state) {
ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state_, function_name_);
}
ScopedGLErrorSuppressor::~ScopedGLErrorSuppressor() {
ERRORSTATE_CLEAR_REAL_GL_ERRORS(error_state_, function_name_);
}
static void RestoreCurrentTextureBindings(ContextState* state, GLenum target) {
TextureUnit& info = state->texture_units[0];
GLuint last_id;
scoped_refptr<TextureRef> texture_ref;
switch (target) {
case GL_TEXTURE_2D:
texture_ref = info.bound_texture_2d;
break;
case GL_TEXTURE_CUBE_MAP:
texture_ref = info.bound_texture_cube_map;
break;
case GL_TEXTURE_EXTERNAL_OES:
texture_ref = info.bound_texture_external_oes;
break;
case GL_TEXTURE_RECTANGLE_ARB:
texture_ref = info.bound_texture_rectangle_arb;
break;
default:
NOTREACHED();
break;
}
if (texture_ref.get()) {
last_id = texture_ref->service_id();
} else {
last_id = 0;
}
glBindTexture(target, last_id);
glActiveTexture(GL_TEXTURE0 + state->active_texture_unit);
}
ScopedTextureBinder::ScopedTextureBinder(ContextState* state,
GLuint id,
GLenum target)
: state_(state),
target_(target) {
ScopedGLErrorSuppressor suppressor(
"ScopedTextureBinder::ctor", state_->GetErrorState());
// TODO(apatrick): Check if there are any other states that need to be reset
// before binding a new texture.
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, id);
}
ScopedTextureBinder::~ScopedTextureBinder() {
ScopedGLErrorSuppressor suppressor(
"ScopedTextureBinder::dtor", state_->GetErrorState());
RestoreCurrentTextureBindings(state_, target_);
}
ScopedRenderBufferBinder::ScopedRenderBufferBinder(ContextState* state,
GLuint id)
: state_(state) {
ScopedGLErrorSuppressor suppressor(
"ScopedRenderBufferBinder::ctor", state_->GetErrorState());
glBindRenderbufferEXT(GL_RENDERBUFFER, id);
}
ScopedRenderBufferBinder::~ScopedRenderBufferBinder() {
ScopedGLErrorSuppressor suppressor(
"ScopedRenderBufferBinder::dtor", state_->GetErrorState());
state_->RestoreRenderbufferBindings();
}
ScopedFrameBufferBinder::ScopedFrameBufferBinder(GLES2DecoderImpl* decoder,
GLuint id)
: decoder_(decoder) {
ScopedGLErrorSuppressor suppressor(
"ScopedFrameBufferBinder::ctor", decoder_->GetErrorState());
glBindFramebufferEXT(GL_FRAMEBUFFER, id);
decoder->OnFboChanged();
}
ScopedFrameBufferBinder::~ScopedFrameBufferBinder() {
ScopedGLErrorSuppressor suppressor(
"ScopedFrameBufferBinder::dtor", decoder_->GetErrorState());
decoder_->RestoreCurrentFramebufferBindings();
}
ScopedResolvedFrameBufferBinder::ScopedResolvedFrameBufferBinder(
GLES2DecoderImpl* decoder, bool enforce_internal_framebuffer, bool internal)
: decoder_(decoder) {
resolve_and_bind_ = (
decoder_->offscreen_target_frame_buffer_.get() &&
decoder_->IsOffscreenBufferMultisampled() &&
(!decoder_->framebuffer_state_.bound_read_framebuffer.get() ||
enforce_internal_framebuffer));
if (!resolve_and_bind_)
return;
ScopedGLErrorSuppressor suppressor(
"ScopedResolvedFrameBufferBinder::ctor", decoder_->GetErrorState());
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT,
decoder_->offscreen_target_frame_buffer_->id());
GLuint targetid;
if (internal) {
if (!decoder_->offscreen_resolved_frame_buffer_.get()) {
decoder_->offscreen_resolved_frame_buffer_.reset(
new BackFramebuffer(decoder_));
decoder_->offscreen_resolved_frame_buffer_->Create();
decoder_->offscreen_resolved_color_texture_.reset(
new BackTexture(decoder->memory_tracker(), &decoder->state_));
decoder_->offscreen_resolved_color_texture_->Create();
DCHECK(decoder_->offscreen_saved_color_format_);
decoder_->offscreen_resolved_color_texture_->AllocateStorage(
decoder_->offscreen_size_, decoder_->offscreen_saved_color_format_,
false);
decoder_->offscreen_resolved_frame_buffer_->AttachRenderTexture(
decoder_->offscreen_resolved_color_texture_.get());
if (decoder_->offscreen_resolved_frame_buffer_->CheckStatus() !=
GL_FRAMEBUFFER_COMPLETE) {
LOG(ERROR) << "ScopedResolvedFrameBufferBinder failed "
<< "because offscreen resolved FBO was incomplete.";
return;
}
}
targetid = decoder_->offscreen_resolved_frame_buffer_->id();
} else {
targetid = decoder_->offscreen_saved_frame_buffer_->id();
}
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, targetid);
const int width = decoder_->offscreen_size_.width();
const int height = decoder_->offscreen_size_.height();
decoder->state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false);
decoder->BlitFramebufferHelper(0,
0,
width,
height,
0,
0,
width,
height,
GL_COLOR_BUFFER_BIT,
GL_NEAREST);
glBindFramebufferEXT(GL_FRAMEBUFFER, targetid);
}
ScopedResolvedFrameBufferBinder::~ScopedResolvedFrameBufferBinder() {
if (!resolve_and_bind_)
return;
ScopedGLErrorSuppressor suppressor(
"ScopedResolvedFrameBufferBinder::dtor", decoder_->GetErrorState());
decoder_->RestoreCurrentFramebufferBindings();
if (decoder_->state_.enable_flags.scissor_test) {
decoder_->state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, true);
}
}
BackTexture::BackTexture(
MemoryTracker* memory_tracker,
ContextState* state)
: memory_tracker_(memory_tracker, MemoryTracker::kUnmanaged),
state_(state),
bytes_allocated_(0),
id_(0) {
}
BackTexture::~BackTexture() {
// This does not destroy the render texture because that would require that
// the associated GL context was current. Just check that it was explicitly
// destroyed.
DCHECK_EQ(id_, 0u);
}
void BackTexture::Create() {
ScopedGLErrorSuppressor suppressor("BackTexture::Create",
state_->GetErrorState());
Destroy();
glGenTextures(1, &id_);
ScopedTextureBinder binder(state_, id_, GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// TODO(apatrick): Attempt to diagnose crbug.com/97775. If SwapBuffers is
// never called on an offscreen context, no data will ever be uploaded to the
// saved offscreen color texture (it is deferred until to when SwapBuffers
// is called). My idea is that some nvidia drivers might have a bug where
// deleting a texture that has never been populated might cause a
// crash.
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
bytes_allocated_ = 16u * 16u * 4u;
memory_tracker_.TrackMemAlloc(bytes_allocated_);
}
bool BackTexture::AllocateStorage(
const gfx::Size& size, GLenum format, bool zero) {
DCHECK_NE(id_, 0u);
ScopedGLErrorSuppressor suppressor("BackTexture::AllocateStorage",
state_->GetErrorState());
ScopedTextureBinder binder(state_, id_, GL_TEXTURE_2D);
uint32 image_size = 0;
GLES2Util::ComputeImageDataSizes(
size.width(), size.height(), 1, format, GL_UNSIGNED_BYTE, 8, &image_size,
NULL, NULL);
if (!memory_tracker_.EnsureGPUMemoryAvailable(image_size)) {
return false;
}
scoped_ptr<char[]> zero_data;
if (zero) {
zero_data.reset(new char[image_size]);
memset(zero_data.get(), 0, image_size);
}
glTexImage2D(GL_TEXTURE_2D,
0, // mip level
format,
size.width(),
size.height(),
0, // border
format,
GL_UNSIGNED_BYTE,
zero_data.get());
size_ = size;
bool success = glGetError() == GL_NO_ERROR;
if (success) {
memory_tracker_.TrackMemFree(bytes_allocated_);
bytes_allocated_ = image_size;
memory_tracker_.TrackMemAlloc(bytes_allocated_);
}
return success;
}
void BackTexture::Copy(const gfx::Size& size, GLenum format) {
DCHECK_NE(id_, 0u);
ScopedGLErrorSuppressor suppressor("BackTexture::Copy",
state_->GetErrorState());
ScopedTextureBinder binder(state_, id_, GL_TEXTURE_2D);
glCopyTexImage2D(GL_TEXTURE_2D,
0, // level
format,
0, 0,
size.width(),
size.height(),
0); // border
}
void BackTexture::Destroy() {
if (id_ != 0) {
ScopedGLErrorSuppressor suppressor("BackTexture::Destroy",
state_->GetErrorState());
glDeleteTextures(1, &id_);
id_ = 0;
}
memory_tracker_.TrackMemFree(bytes_allocated_);
bytes_allocated_ = 0;
}
void BackTexture::Invalidate() {
id_ = 0;
}
BackRenderbuffer::BackRenderbuffer(
RenderbufferManager* renderbuffer_manager,
MemoryTracker* memory_tracker,
ContextState* state)
: renderbuffer_manager_(renderbuffer_manager),
memory_tracker_(memory_tracker, MemoryTracker::kUnmanaged),
state_(state),
bytes_allocated_(0),
id_(0) {
}
BackRenderbuffer::~BackRenderbuffer() {
// This does not destroy the render buffer because that would require that
// the associated GL context was current. Just check that it was explicitly
// destroyed.
DCHECK_EQ(id_, 0u);
}
void BackRenderbuffer::Create() {
ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Create",
state_->GetErrorState());
Destroy();
glGenRenderbuffersEXT(1, &id_);
}
bool BackRenderbuffer::AllocateStorage(const FeatureInfo* feature_info,
const gfx::Size& size,
GLenum format,
GLsizei samples) {
ScopedGLErrorSuppressor suppressor(
"BackRenderbuffer::AllocateStorage", state_->GetErrorState());
ScopedRenderBufferBinder binder(state_, id_);
uint32 estimated_size = 0;
if (!renderbuffer_manager_->ComputeEstimatedRenderbufferSize(
size.width(), size.height(), samples, format, &estimated_size)) {
return false;
}
if (!memory_tracker_.EnsureGPUMemoryAvailable(estimated_size)) {
return false;
}
if (samples <= 1) {
glRenderbufferStorageEXT(GL_RENDERBUFFER,
format,
size.width(),
size.height());
} else {
GLES2DecoderImpl::RenderbufferStorageMultisampleHelper(feature_info,
GL_RENDERBUFFER,
samples,
format,
size.width(),
size.height());
}
bool success = glGetError() == GL_NO_ERROR;
if (success) {
// Mark the previously allocated bytes as free.
memory_tracker_.TrackMemFree(bytes_allocated_);
bytes_allocated_ = estimated_size;
// Track the newly allocated bytes.
memory_tracker_.TrackMemAlloc(bytes_allocated_);
}
return success;
}
void BackRenderbuffer::Destroy() {
if (id_ != 0) {
ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Destroy",
state_->GetErrorState());
glDeleteRenderbuffersEXT(1, &id_);
id_ = 0;
}
memory_tracker_.TrackMemFree(bytes_allocated_);
bytes_allocated_ = 0;
}
void BackRenderbuffer::Invalidate() {
id_ = 0;
}
BackFramebuffer::BackFramebuffer(GLES2DecoderImpl* decoder)
: decoder_(decoder),
id_(0) {
}
BackFramebuffer::~BackFramebuffer() {
// This does not destroy the frame buffer because that would require that
// the associated GL context was current. Just check that it was explicitly
// destroyed.
DCHECK_EQ(id_, 0u);
}
void BackFramebuffer::Create() {
ScopedGLErrorSuppressor suppressor("BackFramebuffer::Create",
decoder_->GetErrorState());
Destroy();
glGenFramebuffersEXT(1, &id_);
}
void BackFramebuffer::AttachRenderTexture(BackTexture* texture) {
DCHECK_NE(id_, 0u);
ScopedGLErrorSuppressor suppressor(
"BackFramebuffer::AttachRenderTexture", decoder_->GetErrorState());
ScopedFrameBufferBinder binder(decoder_, id_);
GLuint attach_id = texture ? texture->id() : 0;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
attach_id,
0);
}
void BackFramebuffer::AttachRenderBuffer(GLenum target,
BackRenderbuffer* render_buffer) {
DCHECK_NE(id_, 0u);
ScopedGLErrorSuppressor suppressor(
"BackFramebuffer::AttachRenderBuffer", decoder_->GetErrorState());
ScopedFrameBufferBinder binder(decoder_, id_);
GLuint attach_id = render_buffer ? render_buffer->id() : 0;
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER,
target,
GL_RENDERBUFFER,
attach_id);
}
void BackFramebuffer::Destroy() {
if (id_ != 0) {
ScopedGLErrorSuppressor suppressor("BackFramebuffer::Destroy",
decoder_->GetErrorState());
glDeleteFramebuffersEXT(1, &id_);
id_ = 0;
}
}
void BackFramebuffer::Invalidate() {
id_ = 0;
}
GLenum BackFramebuffer::CheckStatus() {
DCHECK_NE(id_, 0u);
ScopedGLErrorSuppressor suppressor("BackFramebuffer::CheckStatus",
decoder_->GetErrorState());
ScopedFrameBufferBinder binder(decoder_, id_);
return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
}
GLES2Decoder* GLES2Decoder::Create(ContextGroup* group) {
return new GLES2DecoderImpl(group);
}
GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
: GLES2Decoder(),
group_(group),
logger_(&debug_marker_manager_),
state_(group_->feature_info(), this, &logger_),
unpack_flip_y_(false),
unpack_premultiply_alpha_(false),
unpack_unpremultiply_alpha_(false),
attrib_0_buffer_id_(0),
attrib_0_buffer_matches_value_(true),
attrib_0_size_(0),
fixed_attrib_buffer_id_(0),
fixed_attrib_buffer_size_(0),
offscreen_target_color_format_(0),
offscreen_target_depth_format_(0),
offscreen_target_stencil_format_(0),
offscreen_target_samples_(0),
offscreen_target_buffer_preserved_(true),
offscreen_saved_color_format_(0),
back_buffer_color_format_(0),
back_buffer_has_depth_(false),
back_buffer_has_stencil_(false),
surfaceless_(false),
backbuffer_needs_clear_bits_(0),
current_decoder_error_(error::kNoError),
use_shader_translator_(true),
validators_(group_->feature_info()->validators()),
feature_info_(group_->feature_info()),
frame_number_(0),
has_robustness_extension_(false),
reset_status_(GL_NO_ERROR),
reset_by_robustness_extension_(false),
supports_post_sub_buffer_(false),
force_webgl_glsl_validation_(false),
derivatives_explicitly_enabled_(false),
frag_depth_explicitly_enabled_(false),
draw_buffers_explicitly_enabled_(false),
shader_texture_lod_explicitly_enabled_(false),
compile_shader_always_succeeds_(false),
lose_context_when_out_of_memory_(false),
service_logging_(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableGPUServiceLoggingGPU)),
viewport_max_width_(0),
viewport_max_height_(0),
texture_state_(group_->feature_info()
->workarounds()
.texsubimage2d_faster_than_teximage2d),
cb_command_trace_category_(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
TRACE_DISABLED_BY_DEFAULT("cb_command"))),
gpu_decoder_category_(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
TRACE_DISABLED_BY_DEFAULT("gpu_decoder"))),
gpu_trace_level_(2),
gpu_trace_commands_(false),
gpu_debug_commands_(false),
validation_texture_(0),
validation_fbo_multisample_(0),
validation_fbo_(0) {
DCHECK(group);
attrib_0_value_.v[0] = 0.0f;
attrib_0_value_.v[1] = 0.0f;
attrib_0_value_.v[2] = 0.0f;
attrib_0_value_.v[3] = 1.0f;
// The shader translator is used for WebGL even when running on EGL
// because additional restrictions are needed (like only enabling
// GL_OES_standard_derivatives on demand). It is used for the unit
// tests because GLES2DecoderWithShaderTest.GetShaderInfoLogValidArgs passes
// the empty string to CompileShader and this is not a valid shader.
if (gfx::GetGLImplementation() == gfx::kGLImplementationMockGL ||
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGLSLTranslator)) {
use_shader_translator_ = false;
}
}
GLES2DecoderImpl::~GLES2DecoderImpl() {
}
bool GLES2DecoderImpl::Initialize(
const scoped_refptr<gfx::GLSurface>& surface,
const scoped_refptr<gfx::GLContext>& context,
bool offscreen,
const gfx::Size& size,
const DisallowedFeatures& disallowed_features,
const std::vector<int32>& attribs) {
TRACE_EVENT0("gpu", "GLES2DecoderImpl::Initialize");
DCHECK(context->IsCurrent(surface.get()));
DCHECK(!context_.get());
surfaceless_ = surface->IsSurfaceless() && !offscreen;
set_initialized();
gpu_tracer_.reset(new GPUTracer(this));
gpu_state_tracer_ = GPUStateTracer::Create(&state_);
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableGPUDebugging)) {
set_debug(true);
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableGPUCommandLogging)) {
set_log_commands(true);
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableUnsafeES3APIs)) {
set_unsafe_es3_apis_enabled(true);
}
compile_shader_always_succeeds_ =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kCompileShaderAlwaysSucceeds);
// Take ownership of the context and surface. The surface can be replaced with
// SetSurface.
context_ = context;
surface_ = surface;
ContextCreationAttribHelper attrib_parser;
if (!attrib_parser.Parse(attribs))
return false;
// Save the loseContextWhenOutOfMemory context creation attribute.
lose_context_when_out_of_memory_ =
attrib_parser.lose_context_when_out_of_memory;
// If the failIfMajorPerformanceCaveat context creation attribute was true
// and we are using a software renderer, fail.
if (attrib_parser.fail_if_major_perf_caveat &&
feature_info_->feature_flags().is_swiftshader) {
group_ = NULL; // Must not destroy ContextGroup if it is not initialized.
Destroy(true);
return false;
}
if (!group_->Initialize(this, disallowed_features)) {
LOG(ERROR) << "GpuScheduler::InitializeCommon failed because group "
<< "failed to initialize.";
group_ = NULL; // Must not destroy ContextGroup if it is not initialized.
Destroy(true);
return false;
}
CHECK_GL_ERROR();
disallowed_features_ = disallowed_features;
state_.attrib_values.resize(group_->max_vertex_attribs());
vertex_array_manager_.reset(new VertexArrayManager());
GLuint default_vertex_attrib_service_id = 0;
if (features().native_vertex_array_object) {
glGenVertexArraysOES(1, &default_vertex_attrib_service_id);
glBindVertexArrayOES(default_vertex_attrib_service_id);
}
state_.default_vertex_attrib_manager =
CreateVertexAttribManager(0, default_vertex_attrib_service_id, false);
state_.default_vertex_attrib_manager->Initialize(
group_->max_vertex_attribs(),
feature_info_->workarounds().init_vertex_attributes);
// vertex_attrib_manager is set to default_vertex_attrib_manager by this call
DoBindVertexArrayOES(0);
query_manager_.reset(new QueryManager(this, feature_info_.get()));
image_manager_.reset(new ImageManager);
util_.set_num_compressed_texture_formats(
validators_->compressed_texture_format.GetValues().size());
if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
// We have to enable vertex array 0 on OpenGL or it won't render. Note that
// OpenGL ES 2.0 does not have this issue.
glEnableVertexAttribArray(0);
}
glGenBuffersARB(1, &attrib_0_buffer_id_);
glBindBuffer(GL_ARRAY_BUFFER, attrib_0_buffer_id_);
glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffersARB(1, &fixed_attrib_buffer_id_);
state_.texture_units.resize(group_->max_texture_units());
for (uint32 tt = 0; tt < state_.texture_units.size(); ++tt) {
glActiveTexture(GL_TEXTURE0 + tt);
// We want the last bind to be 2D.
TextureRef* ref;
if (features().oes_egl_image_external) {
ref = texture_manager()->GetDefaultTextureInfo(
GL_TEXTURE_EXTERNAL_OES);
state_.texture_units[tt].bound_texture_external_oes = ref;
glBindTexture(GL_TEXTURE_EXTERNAL_OES, ref ? ref->service_id() : 0);
}
if (features().arb_texture_rectangle) {
ref = texture_manager()->GetDefaultTextureInfo(
GL_TEXTURE_RECTANGLE_ARB);
state_.texture_units[tt].bound_texture_rectangle_arb = ref;
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, ref ? ref->service_id() : 0);
}
ref = texture_manager()->GetDefaultTextureInfo(GL_TEXTURE_CUBE_MAP);
state_.texture_units[tt].bound_texture_cube_map = ref;
glBindTexture(GL_TEXTURE_CUBE_MAP, ref ? ref->service_id() : 0);
ref = texture_manager()->GetDefaultTextureInfo(GL_TEXTURE_2D);
state_.texture_units[tt].bound_texture_2d = ref;
glBindTexture(GL_TEXTURE_2D, ref ? ref->service_id() : 0);
}
glActiveTexture(GL_TEXTURE0);
CHECK_GL_ERROR();
if (offscreen) {
if (attrib_parser.samples > 0 && attrib_parser.sample_buffers > 0 &&
features().chromium_framebuffer_multisample) {
// Per ext_framebuffer_multisample spec, need max bound on sample count.
// max_sample_count must be initialized to a sane value. If
// glGetIntegerv() throws a GL error, it leaves its argument unchanged.
GLint max_sample_count = 1;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_sample_count);
offscreen_target_samples_ = std::min(attrib_parser.samples,
max_sample_count);
} else {
offscreen_target_samples_ = 1;
}
offscreen_target_buffer_preserved_ = attrib_parser.buffer_preserved;
if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
const bool rgb8_supported =
context_->HasExtension("GL_OES_rgb8_rgba8");
// The only available default render buffer formats in GLES2 have very
// little precision. Don't enable multisampling unless 8-bit render
// buffer formats are available--instead fall back to 8-bit textures.
if (rgb8_supported && offscreen_target_samples_ > 1) {
offscreen_target_color_format_ = attrib_parser.alpha_size > 0 ?
GL_RGBA8 : GL_RGB8;
} else {
offscreen_target_samples_ = 1;
offscreen_target_color_format_ = attrib_parser.alpha_size > 0 ?
GL_RGBA : GL_RGB;
}
// ANGLE only supports packed depth/stencil formats, so use it if it is
// available.
const bool depth24_stencil8_supported =
feature_info_->feature_flags().packed_depth24_stencil8;
VLOG(1) << "GL_OES_packed_depth_stencil "
<< (depth24_stencil8_supported ? "" : "not ") << "supported.";
if ((attrib_parser.depth_size > 0 || attrib_parser.stencil_size > 0) &&
depth24_stencil8_supported) {
offscreen_target_depth_format_ = GL_DEPTH24_STENCIL8;
offscreen_target_stencil_format_ = 0;
} else {
// It may be the case that this depth/stencil combination is not
// supported, but this will be checked later by CheckFramebufferStatus.
offscreen_target_depth_format_ = attrib_parser.depth_size > 0 ?
GL_DEPTH_COMPONENT16 : 0;
offscreen_target_stencil_format_ = attrib_parser.stencil_size > 0 ?
GL_STENCIL_INDEX8 : 0;
}
} else {
offscreen_target_color_format_ = attrib_parser.alpha_size > 0 ?
GL_RGBA : GL_RGB;
// If depth is requested at all, use the packed depth stencil format if
// it's available, as some desktop GL drivers don't support any non-packed
// formats for depth attachments.
const bool depth24_stencil8_supported =
feature_info_->feature_flags().packed_depth24_stencil8;
VLOG(1) << "GL_EXT_packed_depth_stencil "
<< (depth24_stencil8_supported ? "" : "not ") << "supported.";
if ((attrib_parser.depth_size > 0 || attrib_parser.stencil_size > 0) &&
depth24_stencil8_supported) {
offscreen_target_depth_format_ = GL_DEPTH24_STENCIL8;
offscreen_target_stencil_format_ = 0;
} else {
offscreen_target_depth_format_ = attrib_parser.depth_size > 0 ?
GL_DEPTH_COMPONENT : 0;
offscreen_target_stencil_format_ = attrib_parser.stencil_size > 0 ?
GL_STENCIL_INDEX : 0;
}
}
offscreen_saved_color_format_ = attrib_parser.alpha_size > 0 ?
GL_RGBA : GL_RGB;
// Create the target frame buffer. This is the one that the client renders
// directly to.
offscreen_target_frame_buffer_.reset(new BackFramebuffer(this));
offscreen_target_frame_buffer_->Create();
// Due to GLES2 format limitations, either the color texture (for
// non-multisampling) or the color render buffer (for multisampling) will be
// attached to the offscreen frame buffer. The render buffer has more
// limited formats available to it, but the texture can't do multisampling.
if (IsOffscreenBufferMultisampled()) {
offscreen_target_color_render_buffer_.reset(new BackRenderbuffer(
renderbuffer_manager(), memory_tracker(), &state_));
offscreen_target_color_render_buffer_->Create();
} else {
offscreen_target_color_texture_.reset(new BackTexture(
memory_tracker(), &state_));
offscreen_target_color_texture_->Create();
}
offscreen_target_depth_render_buffer_.reset(new BackRenderbuffer(
renderbuffer_manager(), memory_tracker(), &state_));
offscreen_target_depth_render_buffer_->Create();
offscreen_target_stencil_render_buffer_.reset(new BackRenderbuffer(
renderbuffer_manager(), memory_tracker(), &state_));
offscreen_target_stencil_render_buffer_->Create();
// Create the saved offscreen texture. The target frame buffer is copied
// here when SwapBuffers is called.
offscreen_saved_frame_buffer_.reset(new BackFramebuffer(this));
offscreen_saved_frame_buffer_->Create();
//
offscreen_saved_color_texture_.reset(new BackTexture(
memory_tracker(), &state_));
offscreen_saved_color_texture_->Create();
// Allocate the render buffers at their initial size and check the status
// of the frame buffers is okay.
if (!ResizeOffscreenFrameBuffer(size)) {
LOG(ERROR) << "Could not allocate offscreen buffer storage.";
Destroy(true);
return false;
}
// Allocate the offscreen saved color texture.
DCHECK(offscreen_saved_color_format_);
offscreen_saved_color_texture_->AllocateStorage(
gfx::Size(1, 1), offscreen_saved_color_format_, true);
offscreen_saved_frame_buffer_->AttachRenderTexture(
offscreen_saved_color_texture_.get());
if (offscreen_saved_frame_buffer_->CheckStatus() !=
GL_FRAMEBUFFER_COMPLETE) {
LOG(ERROR) << "Offscreen saved FBO was incomplete.";
Destroy(true);
return false;
}
// Bind to the new default frame buffer (the offscreen target frame buffer).
// This should now be associated with ID zero.
DoBindFramebuffer(GL_FRAMEBUFFER, 0);
} else {
glBindFramebufferEXT(GL_FRAMEBUFFER, GetBackbufferServiceId());
// These are NOT if the back buffer has these proprorties. They are
// if we want the command buffer to enforce them regardless of what
// the real backbuffer is assuming the real back buffer gives us more than
// we ask for. In other words, if we ask for RGB and we get RGBA then we'll
// make it appear RGB. If on the other hand we ask for RGBA nd get RGB we
// can't do anything about that.
if (!surfaceless_) {
GLint v = 0;
glGetIntegerv(GL_ALPHA_BITS, &v);
// This checks if the user requested RGBA and we have RGBA then RGBA. If
// the user requested RGB then RGB. If the user did not specify a
// preference than use whatever we were given. Same for DEPTH and STENCIL.
back_buffer_color_format_ =
(attrib_parser.alpha_size != 0 && v > 0) ? GL_RGBA : GL_RGB;
glGetIntegerv(GL_DEPTH_BITS, &v);
back_buffer_has_depth_ = attrib_parser.depth_size != 0 && v > 0;
glGetIntegerv(GL_STENCIL_BITS, &v);
back_buffer_has_stencil_ = attrib_parser.stencil_size != 0 && v > 0;
}
}
// OpenGL ES 2.0 implicitly enables the desktop GL capability
// VERTEX_PROGRAM_POINT_SIZE and doesn't expose this enum. This fact
// isn't well documented; it was discovered in the Khronos OpenGL ES
// mailing list archives. It also implicitly enables the desktop GL
// capability GL_POINT_SPRITE to provide access to the gl_PointCoord
// variable in fragment shaders.
if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glEnable(GL_PO