blob: f217a8f594415cee6dd9ce2bd6ff30c8482f614c [file] [log] [blame]
// Copyright (c) 2017 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/raster_decoder.h"
#include <stdint.h>
#include <string>
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/command_buffer/common/command_buffer_id.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/context_result.h"
#include "gpu/command_buffer/common/debug_marker_manager.h"
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/raster_cmd_format.h"
#include "gpu/command_buffer/common/raster_cmd_ids.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/context_state.h"
#include "gpu/command_buffer/service/decoder_client.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/logger.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/query_manager.h"
#include "gpu/command_buffer/service/raster_cmd_validation.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_version_info.h"
// 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, \
static_cast<uint32_t>(value), label)
#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)
using namespace gpu::gles2;
namespace gpu {
namespace raster {
namespace {
class TextureMetadata {
public:
TextureMetadata(bool use_buffer,
gfx::BufferUsage buffer_usage,
viz::ResourceFormat format,
const Capabilities& caps)
: use_buffer_(use_buffer),
buffer_usage_(buffer_usage),
format_(format),
target_(CalcTarget(use_buffer, buffer_usage, format, caps)) {}
TextureMetadata(const TextureMetadata& tmd) = default;
bool use_buffer() const { return use_buffer_; }
gfx::BufferUsage buffer_usage() const { return buffer_usage_; }
viz::ResourceFormat format() const { return format_; }
GLenum target() const { return target_; }
private:
static GLenum CalcTarget(bool use_buffer,
gfx::BufferUsage buffer_usage,
viz::ResourceFormat format,
const gpu::Capabilities& caps) {
if (use_buffer) {
gfx::BufferFormat buffer_format = viz::BufferFormat(format);
return GetBufferTextureTarget(buffer_usage, buffer_format, caps);
} else {
return GL_TEXTURE_2D;
}
}
const bool use_buffer_;
const gfx::BufferUsage buffer_usage_;
const viz::ResourceFormat format_;
const GLenum target_;
};
// This class prevents any GL errors that occur when it is in scope from
// being reported to the client.
class ScopedGLErrorSuppressor {
public:
ScopedGLErrorSuppressor(const char* function_name, ErrorState* error_state);
~ScopedGLErrorSuppressor();
private:
const char* function_name_;
ErrorState* error_state_;
DISALLOW_COPY_AND_ASSIGN(ScopedGLErrorSuppressor);
};
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_);
}
void RestoreCurrentTextureBindings(ContextState* state,
GLenum target,
GLuint texture_unit) {
DCHECK(!state->texture_units.empty());
DCHECK_LT(texture_unit, state->texture_units.size());
TextureUnit& info = state->texture_units[texture_unit];
GLuint last_id;
TextureRef* texture_ref = info.GetInfoForTarget(target);
if (texture_ref) {
last_id = texture_ref->service_id();
} else {
last_id = 0;
}
state->api()->glBindTextureFn(target, last_id);
}
// 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:
ScopedTextureBinder(ContextState* state,
TextureManager* texture_manager,
TextureRef* texture_ref,
GLenum target);
~ScopedTextureBinder();
private:
ContextState* state_;
GLenum target_;
TextureUnit old_unit_;
DISALLOW_COPY_AND_ASSIGN(ScopedTextureBinder);
};
ScopedTextureBinder::ScopedTextureBinder(ContextState* state,
TextureManager* texture_manager,
TextureRef* texture_ref,
GLenum target)
: state_(state), target_(target), old_unit_(state->texture_units[0]) {
auto* api = state->api();
api->glActiveTextureFn(GL_TEXTURE0);
Texture* texture = texture_ref->texture();
if (texture->target() == 0) {
texture_manager->SetTarget(texture_ref, target);
}
DCHECK_EQ(texture->target(), target)
<< "Texture bound to more than 1 target.";
api->glBindTextureFn(target, texture_ref->service_id());
TextureUnit& unit = state_->texture_units[0];
unit.bind_target = target;
unit.SetInfoForTarget(target, texture_ref);
}
ScopedTextureBinder::~ScopedTextureBinder() {
state_->texture_units[0] = old_unit_;
RestoreCurrentTextureBindings(state_, target_, 0);
state_->RestoreActiveTexture();
}
} // namespace
class RasterDecoderImpl : public RasterDecoder, public gles2::ErrorStateClient {
public:
RasterDecoderImpl(DecoderClient* client,
CommandBufferServiceBase* command_buffer_service,
gles2::Outputter* outputter,
gles2::ContextGroup* group);
~RasterDecoderImpl() override;
GLES2Util* GetGLES2Util() override { return &util_; }
// DecoderContext implementation.
base::WeakPtr<DecoderContext> AsWeakPtr() override;
gpu::ContextResult Initialize(
const scoped_refptr<gl::GLSurface>& surface,
const scoped_refptr<gl::GLContext>& context,
bool offscreen,
const gles2::DisallowedFeatures& disallowed_features,
const ContextCreationAttribs& attrib_helper) override;
const gles2::ContextState* GetContextState() override;
void Destroy(bool have_context) override;
bool MakeCurrent() override;
gl::GLContext* GetGLContext() override;
Capabilities GetCapabilities() override;
void RestoreState(const gles2::ContextState* prev_state) override;
void RestoreActiveTexture() const override;
void RestoreAllTextureUnitAndSamplerBindings(
const gles2::ContextState* prev_state) const override;
void RestoreActiveTextureUnitBinding(unsigned int target) const override;
void RestoreBufferBinding(unsigned int target) override;
void RestoreBufferBindings() const override;
void RestoreFramebufferBindings() const override;
void RestoreRenderbufferBindings() override;
void RestoreProgramBindings() const override;
void RestoreTextureState(unsigned service_id) const override;
void RestoreTextureUnitBindings(unsigned unit) const override;
void RestoreVertexAttribArray(unsigned index) override;
void RestoreAllExternalTextureBindingsIfNeeded() override;
QueryManager* GetQueryManager() override;
gles2::GpuFenceManager* GetGpuFenceManager() override;
bool HasPendingQueries() const override;
void ProcessPendingQueries(bool did_finish) override;
bool HasMoreIdleWork() const override;
void PerformIdleWork() override;
bool HasPollingWork() const override;
void PerformPollingWork() override;
TextureBase* GetTextureBase(uint32_t client_id) override;
void SetLevelInfo(uint32_t client_id,
int level,
unsigned internal_format,
unsigned width,
unsigned height,
unsigned depth,
unsigned format,
unsigned type,
const gfx::Rect& cleared_rect) override;
bool WasContextLost() const override;
bool WasContextLostByRobustnessExtension() const override;
void MarkContextLost(error::ContextLostReason reason) override;
bool CheckResetStatus() override;
void BeginDecoding() override;
void EndDecoding() override;
const char* GetCommandName(unsigned int command_id) const;
error::Error DoCommands(unsigned int num_commands,
const volatile void* buffer,
int num_entries,
int* entries_processed) override;
base::StringPiece GetLogPrefix() override;
void BindImage(uint32_t client_texture_id,
uint32_t texture_target,
gl::GLImage* image,
bool can_bind_to_sampler) override;
gles2::ContextGroup* GetContextGroup() override;
gles2::ErrorState* GetErrorState() override;
// ErrorClientState implementation.
void OnContextLostError() override;
void OnOutOfMemoryError() override;
Logger* GetLogger() override;
void SetIgnoreCachedStateForTest(bool ignore) override;
private:
std::unordered_map<GLuint, TextureMetadata> texture_metadata_;
TextureMetadata* GetTextureMetadata(GLuint client_id) {
auto it = texture_metadata_.find(client_id);
DCHECK(it != texture_metadata_.end()) << "Undefined texture id";
return &it->second;
}
gl::GLApi* api() const { return state_.api(); }
const FeatureInfo::FeatureFlags& features() const {
return feature_info_->feature_flags();
}
const GpuDriverBugWorkarounds& workarounds() const {
return feature_info_->workarounds();
}
const gl::GLVersionInfo& gl_version_info() {
return feature_info_->gl_version_info();
}
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;
}
const TextureManager* texture_manager() const {
return group_->texture_manager();
}
TextureManager* texture_manager() { return group_->texture_manager(); }
// 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 nullptr 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);
auto texture_iter = texture_metadata_.find(client_id);
DCHECK(texture_iter != texture_metadata_.end());
texture_metadata_.erase(texture_iter);
}
void UnbindTexture(TextureRef* texture_ref) {
// Unbind texture_ref from texture_ref units.
state_.UnbindTexture(texture_ref);
}
// Set remaining commands to process to 0 to force DoCommands to return
// and allow context preemption and GPU watchdog checks in
// CommandExecutor().
void ExitCommandProcessingEarly() { commands_to_process_ = 0; }
template <bool DebugImpl>
error::Error DoCommandsImpl(unsigned int num_commands,
const volatile void* buffer,
int num_entries,
int* entries_processed);
// Helper for glGetIntegerv. Returns false if pname is unhandled.
bool GetHelper(GLenum pname, GLint* params, GLsizei* num_written);
// Gets the number of values that will be returned by glGetXXX. Returns
// false if pname is unknown.
bool GetNumValuesReturnedForGLGet(GLenum pname, GLsizei* num_values);
GLuint DoCreateTexture(bool use_buffer,
gfx::BufferUsage /* buffer_usage */,
viz::ResourceFormat /* resource_format */);
void CreateTexture(GLuint client_id,
GLuint service_id,
bool use_buffer,
gfx::BufferUsage buffer_usage,
viz::ResourceFormat resource_format);
void DoCreateAndConsumeTextureINTERNAL(GLuint client_id,
bool use_buffer,
gfx::BufferUsage buffer_usage,
viz::ResourceFormat resource_format,
const volatile GLbyte* key);
void DeleteTexturesHelper(GLsizei n, const volatile GLuint* client_ids);
bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
void DeleteQueriesEXTHelper(GLsizei n, const volatile GLuint* client_ids);
void DoFinish();
void DoFlush();
void DoGetIntegerv(GLenum pname, GLint* params, GLsizei params_size);
void DoTexParameteri(GLuint texture_id, GLenum pname, GLint param);
void DoBindTexImage2DCHROMIUM(GLuint texture_id, GLint image_id) {
NOTIMPLEMENTED();
}
void DoProduceTextureDirect(GLuint texture, const volatile GLbyte* key);
void DoReleaseTexImage2DCHROMIUM(GLuint texture_id, GLint image_id) {
NOTIMPLEMENTED();
}
void TexStorage2DImage(TextureRef* texture_ref,
const TextureMetadata& texture_metadata,
GLsizei width,
GLsizei height) {
NOTIMPLEMENTED();
}
void TexStorage2D(TextureRef* texture_ref,
const TextureMetadata& texture_metadata,
GLint levels,
GLsizei width,
GLsizei height);
void TexImage2D(TextureRef* texture_ref,
const TextureMetadata& texture_metadata,
GLsizei width,
GLsizei height);
void DoTexStorage2D(GLuint texture_id,
GLint levels,
GLsizei width,
GLsizei height);
void DoCopySubTexture(GLuint source_id,
GLuint dest_id,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height) {
NOTIMPLEMENTED();
}
void DoCompressedCopyTextureCHROMIUM(GLuint source_id, GLuint dest_id) {
NOTIMPLEMENTED();
}
void DoProduceTextureDirectCHROMIUM(GLuint texture,
const volatile GLbyte* key) {
NOTIMPLEMENTED();
}
void DoLoseContextCHROMIUM(GLenum current, GLenum other) { NOTIMPLEMENTED(); }
void DoBeginRasterCHROMIUM(GLuint texture_id,
GLuint sk_color,
GLuint msaa_sample_count,
GLboolean can_use_lcd_text,
GLint color_type) {
NOTIMPLEMENTED();
}
void DoRasterCHROMIUM(GLsizeiptr size, const void* list) { NOTIMPLEMENTED(); }
void DoEndRasterCHROMIUM() { NOTIMPLEMENTED(); }
void DoCreateTransferCacheEntryINTERNAL(GLuint entry_type,
GLuint entry_id,
GLuint handle_shm_id,
GLuint handle_shm_offset,
GLuint data_shm_id,
GLuint data_shm_offset,
GLuint data_size) {
NOTIMPLEMENTED();
}
void DoUnlockTransferCacheEntryINTERNAL(GLuint entry_type, GLuint entry_id) {
NOTIMPLEMENTED();
}
void DoDeleteTransferCacheEntryINTERNAL(GLuint entry_type, GLuint entry_id) {
NOTIMPLEMENTED();
}
void DoUnpremultiplyAndDitherCopyCHROMIUM(GLuint source_id,
GLuint dest_id,
GLint x,
GLint y,
GLsizei width,
GLsizei height) {
NOTIMPLEMENTED();
}
#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
// Generate a member function prototype for each command in an automated and
// typesafe way.
#define RASTER_CMD_OP(name) \
Error Handle##name(uint32_t immediate_data_size, const volatile void* data);
RASTER_COMMAND_LIST(RASTER_CMD_OP)
#undef RASTER_CMD_OP
typedef error::Error (RasterDecoderImpl::*CmdHandler)(
uint32_t immediate_data_size,
const volatile void* data);
// A struct to hold info about each command.
struct CommandInfo {
CmdHandler cmd_handler;
uint8_t arg_flags; // How to handle the arguments for this command
uint8_t cmd_flags; // How to handle this command
uint16_t arg_count; // How many arguments are expected for this command.
};
// A table of CommandInfo for all the commands.
static const CommandInfo command_info[kNumCommands - kFirstRasterCommand];
// Number of commands remaining to be processed in DoCommands().
int commands_to_process_;
// 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_;
scoped_refptr<gl::GLSurface> surface_;
scoped_refptr<gl::GLContext> context_;
DecoderClient* client_;
gles2::DebugMarkerManager debug_marker_manager_;
gles2::Logger logger_;
// The ContextGroup for this decoder uses to track resources.
scoped_refptr<gles2::ContextGroup> group_;
std::unique_ptr<Validators> validators_;
scoped_refptr<gles2::FeatureInfo> feature_info_;
std::unique_ptr<QueryManager> query_manager_;
// All the state for this context.
gles2::ContextState state_;
GLES2Util util_;
// States related to each manager.
DecoderTextureState texture_state_;
DecoderFramebufferState framebuffer_state_;
bool gpu_debug_commands_;
// Log extra info.
bool service_logging_;
base::WeakPtrFactory<DecoderContext> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RasterDecoderImpl);
};
constexpr RasterDecoderImpl::CommandInfo RasterDecoderImpl::command_info[] = {
#define RASTER_CMD_OP(name) \
{ \
&RasterDecoderImpl::Handle##name, cmds::name::kArgFlags, \
cmds::name::cmd_flags, \
sizeof(cmds::name) / sizeof(CommandBufferEntry) - 1, \
}, /* NOLINT */
RASTER_COMMAND_LIST(RASTER_CMD_OP)
#undef RASTER_CMD_OP
};
// static
RasterDecoder* RasterDecoder::Create(
DecoderClient* client,
CommandBufferServiceBase* command_buffer_service,
Outputter* outputter,
ContextGroup* group) {
return new RasterDecoderImpl(client, command_buffer_service, outputter,
group);
}
RasterDecoder::RasterDecoder(CommandBufferServiceBase* command_buffer_service)
: CommonDecoder(command_buffer_service),
initialized_(false),
debug_(false),
log_commands_(false) {}
RasterDecoder::~RasterDecoder() {}
bool RasterDecoder::initialized() const {
return initialized_;
}
TextureBase* RasterDecoder::GetTextureBase(uint32_t client_id) {
return nullptr;
}
void RasterDecoder::SetLevelInfo(uint32_t client_id,
int level,
unsigned internal_format,
unsigned width,
unsigned height,
unsigned depth,
unsigned format,
unsigned type,
const gfx::Rect& cleared_rect) {}
void RasterDecoder::BeginDecoding() {}
void RasterDecoder::EndDecoding() {}
base::StringPiece RasterDecoder::GetLogPrefix() {
return GetLogger()->GetLogPrefix();
}
RasterDecoderImpl::RasterDecoderImpl(
DecoderClient* client,
CommandBufferServiceBase* command_buffer_service,
Outputter* outputter,
ContextGroup* group)
: RasterDecoder(command_buffer_service),
commands_to_process_(0),
current_decoder_error_(error::kNoError),
client_(client),
logger_(&debug_marker_manager_, client),
group_(group),
validators_(new Validators),
feature_info_(group_->feature_info()),
state_(group_->feature_info(), this, &logger_),
texture_state_(group_->feature_info()->workarounds()),
service_logging_(
group_->gpu_preferences().enable_gpu_service_logging_gpu),
weak_ptr_factory_(this) {}
RasterDecoderImpl::~RasterDecoderImpl() {}
base::WeakPtr<DecoderContext> RasterDecoderImpl::AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
gpu::ContextResult RasterDecoderImpl::Initialize(
const scoped_refptr<gl::GLSurface>& surface,
const scoped_refptr<gl::GLContext>& context,
bool offscreen,
const DisallowedFeatures& disallowed_features,
const ContextCreationAttribs& attrib_helper) {
TRACE_EVENT0("gpu", "RasterDecoderImpl::Initialize");
DCHECK(context->IsCurrent(surface.get()));
DCHECK(!context_.get());
state_.set_api(gl::g_current_gl_context);
set_initialized();
if (!offscreen) {
return gpu::ContextResult::kFatalFailure;
}
if (group_->gpu_preferences().enable_gpu_debugging)
set_debug(true);
if (group_->gpu_preferences().enable_gpu_command_logging)
set_log_commands(true);
surface_ = surface;
context_ = context;
auto result =
group_->Initialize(this, attrib_helper.context_type, disallowed_features);
if (result != gpu::ContextResult::kSuccess) {
group_ =
nullptr; // Must not destroy ContextGroup if it is not initialized.
Destroy(true);
return result;
}
CHECK_GL_ERROR();
query_manager_.reset(new QueryManager());
state_.texture_units.resize(group_->max_texture_units());
state_.sampler_units.resize(group_->max_texture_units());
for (uint32_t tt = 0; tt < state_.texture_units.size(); ++tt) {
api()->glActiveTextureFn(GL_TEXTURE0 + tt);
TextureRef* ref;
ref = texture_manager()->GetDefaultTextureInfo(GL_TEXTURE_2D);
state_.texture_units[tt].bound_texture_2d = ref;
api()->glBindTextureFn(GL_TEXTURE_2D, ref ? ref->service_id() : 0);
}
api()->glActiveTextureFn(GL_TEXTURE0);
CHECK_GL_ERROR();
return gpu::ContextResult::kSuccess;
}
const gles2::ContextState* RasterDecoderImpl::GetContextState() {
NOTIMPLEMENTED();
return nullptr;
}
void RasterDecoderImpl::Destroy(bool have_context) {
if (query_manager_.get()) {
query_manager_->Destroy(have_context);
query_manager_.reset();
}
if (group_.get()) {
group_->Destroy(this, have_context);
group_ = NULL;
}
// Destroy the surface before the context, some surface destructors make GL
// calls.
surface_ = nullptr;
if (context_.get()) {
context_->ReleaseCurrent(NULL);
context_ = NULL;
}
}
// Make this decoder's GL context current.
bool RasterDecoderImpl::MakeCurrent() {
DCHECK(surface_);
if (!context_.get())
return false;
if (WasContextLost()) {
LOG(ERROR) << " RasterDecoderImpl: Trying to make lost context current.";
return false;
}
if (!context_->MakeCurrent(surface_.get())) {
LOG(ERROR) << " RasterDecoderImpl: Context lost during MakeCurrent.";
MarkContextLost(error::kMakeCurrentFailed);
group_->LoseContexts(error::kUnknown);
return false;
}
return true;
}
gl::GLContext* RasterDecoderImpl::GetGLContext() {
return context_.get();
}
Capabilities RasterDecoderImpl::GetCapabilities() {
gpu::Capabilities caps;
caps.gpu_rasterization = true;
caps.supports_oop_raster = true;
caps.texture_target_exception_list =
group_->gpu_preferences().texture_target_exception_list;
caps.texture_format_bgra8888 =
feature_info_->feature_flags().ext_texture_format_bgra8888;
caps.texture_storage_image =
feature_info_->feature_flags().chromium_texture_storage_image;
caps.texture_storage = feature_info_->feature_flags().ext_texture_storage;
return caps;
}
void RasterDecoderImpl::RestoreState(const ContextState* prev_state) {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreActiveTexture() const {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreAllTextureUnitAndSamplerBindings(
const ContextState* prev_state) const {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreActiveTextureUnitBinding(
unsigned int target) const {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreBufferBinding(unsigned int target) {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreBufferBindings() const {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreFramebufferBindings() const {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreRenderbufferBindings() {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreProgramBindings() const {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreTextureState(unsigned service_id) const {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreTextureUnitBindings(unsigned unit) const {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreVertexAttribArray(unsigned index) {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::RestoreAllExternalTextureBindingsIfNeeded() {
NOTIMPLEMENTED();
}
QueryManager* RasterDecoderImpl::GetQueryManager() {
return query_manager_.get();
}
GpuFenceManager* RasterDecoderImpl::GetGpuFenceManager() {
NOTIMPLEMENTED();
return nullptr;
}
bool RasterDecoderImpl::HasPendingQueries() const {
return query_manager_.get() && query_manager_->HavePendingQueries();
}
void RasterDecoderImpl::ProcessPendingQueries(bool did_finish) {
if (!query_manager_.get())
return;
query_manager_->ProcessPendingQueries(did_finish);
}
bool RasterDecoderImpl::HasMoreIdleWork() const {
return false;
}
void RasterDecoderImpl::PerformIdleWork() {
}
bool RasterDecoderImpl::HasPollingWork() const {
return false;
}
void RasterDecoderImpl::PerformPollingWork() {}
TextureBase* RasterDecoderImpl::GetTextureBase(uint32_t client_id) {
NOTIMPLEMENTED();
return nullptr;
}
void RasterDecoderImpl::SetLevelInfo(uint32_t client_id,
int level,
unsigned internal_format,
unsigned width,
unsigned height,
unsigned depth,
unsigned format,
unsigned type,
const gfx::Rect& cleared_rect) {
NOTIMPLEMENTED();
}
bool RasterDecoderImpl::WasContextLost() const {
return false;
}
bool RasterDecoderImpl::WasContextLostByRobustnessExtension() const {
NOTIMPLEMENTED();
return false;
}
void RasterDecoderImpl::MarkContextLost(error::ContextLostReason reason) {
NOTIMPLEMENTED();
}
bool RasterDecoderImpl::CheckResetStatus() {
NOTIMPLEMENTED();
return false;
}
Logger* RasterDecoderImpl::GetLogger() {
return &logger_;
}
void RasterDecoderImpl::SetIgnoreCachedStateForTest(bool ignore) {
state_.SetIgnoreCachedStateForTest(ignore);
}
void RasterDecoderImpl::BeginDecoding() {
gpu_debug_commands_ = log_commands() || debug();
}
void RasterDecoderImpl::EndDecoding() {}
const char* RasterDecoderImpl::GetCommandName(unsigned int command_id) const {
if (command_id >= kFirstRasterCommand && command_id < kNumCommands) {
return raster::GetCommandName(static_cast<CommandId>(command_id));
}
return GetCommonCommandName(static_cast<cmd::CommandId>(command_id));
}
template <bool DebugImpl>
error::Error RasterDecoderImpl::DoCommandsImpl(unsigned int num_commands,
const volatile void* buffer,
int num_entries,
int* entries_processed) {
DCHECK(entries_processed);
commands_to_process_ = num_commands;
error::Error result = error::kNoError;
const volatile CommandBufferEntry* cmd_data =
static_cast<const volatile CommandBufferEntry*>(buffer);
int process_pos = 0;
unsigned int command = 0;
while (process_pos < num_entries && result == error::kNoError &&
commands_to_process_--) {
const unsigned int size = cmd_data->value_header.size;
command = cmd_data->value_header.command;
if (size == 0) {
result = error::kInvalidSize;
break;
}
if (static_cast<int>(size) + process_pos > num_entries) {
result = error::kOutOfBounds;
break;
}
if (DebugImpl && log_commands()) {
LOG(ERROR) << "[" << logger_.GetLogPrefix() << "]"
<< "cmd: " << GetCommandName(command);
}
const unsigned int arg_count = size - 1;
unsigned int command_index = command - kFirstRasterCommand;
if (command_index < arraysize(command_info)) {
const CommandInfo& info = command_info[command_index];
unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
(info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
uint32_t immediate_data_size = (arg_count - info_arg_count) *
sizeof(CommandBufferEntry); // NOLINT
result = (this->*info.cmd_handler)(immediate_data_size, cmd_data);
if (DebugImpl && debug() && !WasContextLost()) {
GLenum error;
while ((error = api()->glGetErrorFn()) != GL_NO_ERROR) {
LOG(ERROR) << "[" << logger_.GetLogPrefix() << "] "
<< "GL ERROR: " << GLES2Util::GetStringEnum(error)
<< " : " << GetCommandName(command);
LOCAL_SET_GL_ERROR(error, "DoCommand", "GL error from driver");
}
}
} else {
result = error::kInvalidArguments;
}
} else {
result = DoCommonCommand(command, arg_count, cmd_data);
}
if (result == error::kNoError &&
current_decoder_error_ != error::kNoError) {
result = current_decoder_error_;
current_decoder_error_ = error::kNoError;
}
if (result != error::kDeferCommandUntilLater) {
process_pos += size;
cmd_data += size;
}
}
*entries_processed = process_pos;
if (error::IsError(result)) {
LOG(ERROR) << "Error: " << result << " for Command "
<< GetCommandName(command);
}
return result;
}
error::Error RasterDecoderImpl::DoCommands(unsigned int num_commands,
const volatile void* buffer,
int num_entries,
int* entries_processed) {
if (gpu_debug_commands_) {
return DoCommandsImpl<true>(num_commands, buffer, num_entries,
entries_processed);
} else {
return DoCommandsImpl<false>(num_commands, buffer, num_entries,
entries_processed);
}
}
bool RasterDecoderImpl::GetHelper(GLenum pname,
GLint* params,
GLsizei* num_written) {
DCHECK(num_written);
switch (pname) {
case GL_MAX_TEXTURE_SIZE:
*num_written = 1;
if (params) {
params[0] = texture_manager()->MaxSizeForTarget(GL_TEXTURE_2D);
}
return true;
default:
*num_written = util_.GLGetNumValuesReturned(pname);
if (*num_written)
break;
return false;
}
// TODO(backer): Only GL_ACTIVE_TEXTURE supported?
if (pname != GL_ACTIVE_TEXTURE) {
return false;
}
if (params) {
api()->glGetIntegervFn(pname, params);
}
return true;
}
bool RasterDecoderImpl::GetNumValuesReturnedForGLGet(GLenum pname,
GLsizei* num_values) {
*num_values = 0;
if (state_.GetStateAsGLint(pname, NULL, num_values)) {
return true;
}
return GetHelper(pname, NULL, num_values);
}
base::StringPiece RasterDecoderImpl::GetLogPrefix() {
return logger_.GetLogPrefix();
}
void RasterDecoderImpl::BindImage(uint32_t client_texture_id,
uint32_t texture_target,
gl::GLImage* image,
bool can_bind_to_sampler) {
NOTIMPLEMENTED();
}
gles2::ContextGroup* RasterDecoderImpl::GetContextGroup() {
return group_.get();
}
gles2::ErrorState* RasterDecoderImpl::GetErrorState() {
return state_.GetErrorState();
}
void RasterDecoderImpl::OnContextLostError() {
NOTIMPLEMENTED();
}
void RasterDecoderImpl::OnOutOfMemoryError() {
NOTIMPLEMENTED();
}
error::Error RasterDecoderImpl::HandleWaitSyncTokenCHROMIUM(
uint32_t immediate_data_size,
const volatile void* cmd_data) {
const volatile gles2::cmds::WaitSyncTokenCHROMIUM& c =
*static_cast<const volatile gles2::cmds::WaitSyncTokenCHROMIUM*>(
cmd_data);
const gpu::CommandBufferNamespace kMinNamespaceId =
gpu::CommandBufferNamespace::INVALID;
const gpu::CommandBufferNamespace kMaxNamespaceId =
gpu::CommandBufferNamespace::NUM_COMMAND_BUFFER_NAMESPACES;
gpu::CommandBufferNamespace namespace_id =
static_cast<gpu::CommandBufferNamespace>(c.namespace_id);
if ((namespace_id < static_cast<int32_t>(kMinNamespaceId)) ||
(namespace_id >= static_cast<int32_t>(kMaxNamespaceId))) {
namespace_id = gpu::CommandBufferNamespace::INVALID;
}
const CommandBufferId command_buffer_id =
CommandBufferId::FromUnsafeValue(c.command_buffer_id());
const uint64_t release = c.release_count();
gpu::SyncToken sync_token;
sync_token.Set(namespace_id, command_buffer_id, release);
return client_->OnWaitSyncToken(sync_token) ? error::kDeferCommandUntilLater
: error::kNoError;
}
error::Error RasterDecoderImpl::HandleSetColorSpaceMetadata(
uint32_t immediate_data_size,
const volatile void* cmd_data) {
NOTIMPLEMENTED();
return error::kNoError;
}
error::Error RasterDecoderImpl::HandleBeginQueryEXT(
uint32_t immediate_data_size,
const volatile void* cmd_data) {
const volatile raster::cmds::BeginQueryEXT& c =
*static_cast<const volatile raster::cmds::BeginQueryEXT*>(cmd_data);
GLenum target = static_cast<GLenum>(c.target);
GLuint client_id = static_cast<GLuint>(c.id);
int32_t sync_shm_id = static_cast<int32_t>(c.sync_data_shm_id);
uint32_t sync_shm_offset = static_cast<uint32_t>(c.sync_data_shm_offset);
switch (target) {
case GL_COMMANDS_ISSUED_CHROMIUM:
case GL_COMMANDS_COMPLETED_CHROMIUM:
break;
default:
LOCAL_SET_GL_ERROR(GL_INVALID_ENUM, "glBeginQueryEXT",
"unknown query target");
return error::kNoError;
}
if (query_manager_->GetActiveQuery(target)) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginQueryEXT",
"query already in progress");
return error::kNoError;
}
if (client_id == 0) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
return error::kNoError;
}
scoped_refptr<gpu::Buffer> buffer = GetSharedMemoryBuffer(sync_shm_id);
if (!buffer)
return error::kInvalidArguments;
QuerySync* sync = static_cast<QuerySync*>(
buffer->GetDataAddress(sync_shm_offset, sizeof(QuerySync)));
if (!sync)
return error::kOutOfBounds;
QueryManager::Query* query = query_manager_->GetQuery(client_id);
if (!query) {
if (!query_manager_->IsValidQuery(client_id)) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginQueryEXT",
"id not made by glGenQueriesEXT");
return error::kNoError;
}
query =
query_manager_->CreateQuery(target, client_id, std::move(buffer), sync);
} else {
if (query->target() != target) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginQueryEXT",
"target does not match");
return error::kNoError;
} else if (query->sync() != sync) {
DLOG(ERROR) << "Shared memory used by query not the same as before";
return error::kInvalidArguments;
}
}
query_manager_->BeginQuery(query);
return error::kNoError;
}
error::Error RasterDecoderImpl::HandleEndQueryEXT(
uint32_t immediate_data_size,
const volatile void* cmd_data) {
const volatile raster::cmds::EndQueryEXT& c =
*static_cast<const volatile raster::cmds::EndQueryEXT*>(cmd_data);
GLenum target = static_cast<GLenum>(c.target);
uint32_t submit_count = static_cast<GLuint>(c.submit_count);
QueryManager::Query* query = query_manager_->GetActiveQuery(target);
if (!query) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glEndQueryEXT",
"No active query");
return error::kNoError;
}
query_manager_->EndQuery(query, submit_count);
return error::kNoError;
}
error::Error RasterDecoderImpl::HandleInitializeDiscardableTextureCHROMIUM(
uint32_t immediate_data_size,
const volatile void* cmd_data) {
NOTIMPLEMENTED();
return error::kNoError;
}
error::Error RasterDecoderImpl::HandleUnlockDiscardableTextureCHROMIUM(
uint32_t immediate_data_size,
const volatile void* cmd_data) {
NOTIMPLEMENTED();
return error::kNoError;
}
error::Error RasterDecoderImpl::HandleLockDiscardableTextureCHROMIUM(
uint32_t immediate_data_size,
const volatile void* cmd_data) {
NOTIMPLEMENTED();
return error::kNoError;
}
error::Error RasterDecoderImpl::HandleInsertFenceSyncCHROMIUM(
uint32_t immediate_data_size,
const volatile void* cmd_data) {
const volatile gles2::cmds::InsertFenceSyncCHROMIUM& c =
*static_cast<const volatile gles2::cmds::InsertFenceSyncCHROMIUM*>(
cmd_data);
const uint64_t release_count = c.release_count();
client_->OnFenceSyncRelease(release_count);
// Exit inner command processing loop so that we check the scheduling state
// and yield if necessary as we may have unblocked a higher priority context.
ExitCommandProcessingEarly();
return error::kNoError;
}
void RasterDecoderImpl::DoFinish() {
api()->glFinishFn();
ProcessPendingQueries(true);
}
void RasterDecoderImpl::DoFlush() {
api()->glFlushFn();
ProcessPendingQueries(false);
}
void RasterDecoderImpl::DoGetIntegerv(GLenum pname,
GLint* params,
GLsizei params_size) {
DCHECK(params);
GLsizei num_written = 0;
if (state_.GetStateAsGLint(pname, params, &num_written) ||
GetHelper(pname, params, &num_written)) {
DCHECK_EQ(num_written, params_size);
return;
}
NOTREACHED() << "Unhandled enum " << pname;
}
GLuint RasterDecoderImpl::DoCreateTexture(
bool use_buffer,
gfx::BufferUsage /* buffer_usage */,
viz::ResourceFormat /* resource_format */) {
GLuint service_id = 0;
api()->glGenTexturesFn(1, &service_id);
DCHECK(service_id);
return service_id;
}
void RasterDecoderImpl::CreateTexture(GLuint client_id,
GLuint service_id,
bool use_buffer,
gfx::BufferUsage buffer_usage,
viz::ResourceFormat resource_format) {
texture_metadata_.emplace(std::make_pair(
client_id, TextureMetadata(use_buffer, buffer_usage, resource_format,
GetCapabilities())));
texture_manager()->CreateTexture(client_id, service_id);
}
void RasterDecoderImpl::DoCreateAndConsumeTextureINTERNAL(
GLuint client_id,
bool use_buffer,
gfx::BufferUsage buffer_usage,
viz::ResourceFormat resource_format,
const volatile GLbyte* key) {
TRACE_EVENT2("gpu", "RasterDecoderImpl::DoCreateAndConsumeTextureINTERNAL",
"context", logger_.GetLogPrefix(), "key[0]",
static_cast<unsigned char>(key[0]));
Mailbox mailbox =
Mailbox::FromVolatile(*reinterpret_cast<const volatile Mailbox*>(key));
DLOG_IF(ERROR, !mailbox.Verify()) << "CreateAndConsumeTexture was "
"passed a mailbox that was not "
"generated by GenMailboxCHROMIUM.";
if (!client_id) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
"glCreateAndConsumeTextureCHROMIUM",
"invalid client id");
return;
}
TextureRef* texture_ref = GetTexture(client_id);
if (texture_ref) {
// No need to create texture here, the client_id already has an associated
// texture.
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
"glCreateAndConsumeTextureCHROMIUM",
"client id already in use");
return;
}
texture_metadata_.emplace(std::make_pair(
client_id, TextureMetadata(use_buffer, buffer_usage, resource_format,
GetCapabilities())));
Texture* texture =
static_cast<Texture*>(group_->mailbox_manager()->ConsumeTexture(mailbox));
if (!texture) {
// Create texture to handle invalid mailbox (see http://crbug.com/472465).
GLuint service_id = 0;
api()->glGenTexturesFn(1, &service_id);
DCHECK(service_id);
texture_manager()->CreateTexture(client_id, service_id);
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
"glCreateAndConsumeTextureCHROMIUM",
"invalid mailbox name");
return;
}
texture_ref = texture_manager()->Consume(client_id, texture);
// TODO(backer): Validate that the consumed texture is consistent with
// TextureMetadata.
}
void RasterDecoderImpl::DeleteTexturesHelper(
GLsizei n,
const volatile GLuint* client_ids) {
for (GLsizei ii = 0; ii < n; ++ii) {
GLuint client_id = client_ids[ii];
TextureRef* texture_ref = GetTexture(client_id);
if (texture_ref) {
UnbindTexture(texture_ref);
RemoveTexture(client_id);
}
}
}
bool RasterDecoderImpl::GenQueriesEXTHelper(GLsizei n,
const GLuint* client_ids) {
for (GLsizei ii = 0; ii < n; ++ii) {
if (query_manager_->IsValidQuery(client_ids[ii])) {
return false;
}
}
query_manager_->GenQueries(n, client_ids);
return true;
}
void RasterDecoderImpl::DeleteQueriesEXTHelper(
GLsizei n,
const volatile GLuint* client_ids) {
for (GLsizei ii = 0; ii < n; ++ii) {
GLuint client_id = client_ids[ii];
query_manager_->RemoveQuery(client_id);
}
}
void RasterDecoderImpl::DoTexParameteri(GLuint client_id,
GLenum pname,
GLint param) {
TextureRef* texture = texture_manager()->GetTexture(client_id);
if (!texture) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameteri", "unknown texture");
return;
}
TextureMetadata* texture_metadata = GetTextureMetadata(client_id);
if (!texture_metadata) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameteri", "unknown texture");
return;
}
// TextureManager uses validators from the share group, which may include
// GLES2. Perform stronger validation here.
bool valid_param = true;
bool valid_pname = true;
switch (pname) {
case GL_TEXTURE_MIN_FILTER:
valid_param = validators_->texture_min_filter_mode.IsValid(param);
break;
case GL_TEXTURE_MAG_FILTER:
valid_param = validators_->texture_mag_filter_mode.IsValid(param);
break;
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_WRAP_T:
valid_param = validators_->texture_wrap_mode.IsValid(param);
break;
default:
valid_pname = false;
}
if (!valid_pname) {
LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameteri", pname, "pname");
return;
}
if (!valid_param) {
LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameteri", param, "pname");
return;
}
ScopedTextureBinder binder(&state_, texture_manager(), texture,
texture_metadata->target());
texture_manager()->SetParameteri("glTexParameteri", GetErrorState(), texture,
pname, param);
}
void RasterDecoderImpl::DoProduceTextureDirect(GLuint client_id,
const volatile GLbyte* key) {
TRACE_EVENT2("gpu", "RasterDecoderImpl::DoProduceTextureDirect", "context",
logger_.GetLogPrefix(), "key[0]",
static_cast<unsigned char>(key[0]));
Mailbox mailbox =
Mailbox::FromVolatile(*reinterpret_cast<const volatile Mailbox*>(key));
DLOG_IF(ERROR, !mailbox.Verify()) << "ProduceTextureDirect was passed a "
"mailbox that was not generated by "
"GenMailboxCHROMIUM.";
TextureRef* texture_ref = GetTexture(client_id);
bool clear = !client_id;
if (clear) {
DCHECK(!texture_ref);
group_->mailbox_manager()->ProduceTexture(mailbox, nullptr);
return;
}
if (!texture_ref) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "ProduceTextureDirect",
"unknown texture");
return;
}
Texture* produced = texture_manager()->Produce(texture_ref);
if (!produced) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "ProduceTextureDirect",
"invalid texture");
return;
}
group_->mailbox_manager()->ProduceTexture(mailbox, produced);
}
void RasterDecoderImpl::TexStorage2D(TextureRef* texture_ref,
const TextureMetadata& texture_metadata,
GLint levels,
GLsizei width,
GLsizei height) {
TRACE_EVENT2("gpu", "RasterDecoderImpl::TexStorage2D", "width", width,
"height", height);
if (!texture_manager()->ValidForTarget(texture_metadata.target(), 0, width,
height, 1 /* depth */) ||
TextureManager::ComputeMipMapCount(texture_metadata.target(), width,
height, 1 /* depth */) < levels) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2D",
"dimensions out of range");
return;
}
ScopedTextureBinder binder(&state_, texture_manager(), texture_ref,
texture_metadata.target());
unsigned int internal_format =
viz::GLInternalFormat(texture_metadata.format());
GLenum format =
TextureManager::ExtractFormatFromStorageFormat(internal_format);
GLenum type = TextureManager::ExtractTypeFromStorageFormat(internal_format);
// First lookup compatibility format via texture manager for swizzling legacy
// LUMINANCE/ALPHA formats.
GLenum compatibility_internal_format =
texture_manager()->AdjustTexStorageFormat(feature_info_.get(),
internal_format);
Texture* texture = texture_ref->texture();
if (workarounds().reset_base_mipmap_level_before_texstorage &&
texture->base_level() > 0)
api()->glTexParameteriFn(texture_metadata.target(), GL_TEXTURE_BASE_LEVEL,
0);
// TODO(zmo): We might need to emulate TexStorage using TexImage or
// CompressedTexImage on Mac OSX where we expose ES3 APIs when the underlying
// driver is lower than 4.2 and ARB_texture_storage extension doesn't exist.
api()->glTexStorage2DEXTFn(texture_metadata.target(), levels,
compatibility_internal_format, width, height);
if (workarounds().reset_base_mipmap_level_before_texstorage &&
texture->base_level() > 0)
api()->glTexParameteriFn(texture_metadata.target(), GL_TEXTURE_BASE_LEVEL,
texture->base_level());
{
GLsizei level_width = width;
GLsizei level_height = height;
GLenum adjusted_internal_format =
feature_info_->IsWebGL1OrES2Context() ? format : internal_format;
for (int ii = 0; ii < levels; ++ii) {
texture_manager()->SetLevelInfo(texture_ref, texture_metadata.target(),
ii, adjusted_internal_format, level_width,
level_height, 1 /* level_depth */, 0,
format, type, gfx::Rect());
level_width = std::max(1, level_width >> 1);
level_height = std::max(1, level_height >> 1);
}
texture->ApplyFormatWorkarounds(feature_info_.get());
}
}
void RasterDecoderImpl::TexImage2D(TextureRef* texture_ref,
const TextureMetadata& texture_metadata,
GLsizei width,
GLsizei height) {
TRACE_EVENT2("gpu", "RasterDecoderImpl::TexImage2D", "width", width, "height",
height);
// Set as failed for now, but if it successed, this will be set to not failed.
texture_state_.tex_image_failed = true;
DCHECK(!state_.bound_pixel_unpack_buffer.get());
ScopedTextureBinder binder(&state_, texture_manager(), texture_ref,
texture_metadata.target());
TextureManager::DoTexImageArguments args = {
texture_metadata.target(),
0 /* level */,
viz::GLInternalFormat(texture_metadata.format()),
width,
height,
1 /* depth */,
0 /* border */,
viz::GLDataFormat(texture_metadata.format()),
viz::GLDataType(texture_metadata.format()),
nullptr /* pixels */,
0 /* pixels_size */,
0 /* padding */,
TextureManager::DoTexImageArguments::kTexImage2D};
texture_manager()->ValidateAndDoTexImage(
&texture_state_, &state_, &framebuffer_state_, "glTexStorage2D", args);
// This may be a slow command. Exit command processing to allow for
// context preemption and GPU watchdog checks.
ExitCommandProcessingEarly();
}
void RasterDecoderImpl::DoTexStorage2D(GLuint client_id,
GLint levels,
GLsizei width,
GLsizei height) {
TextureRef* texture_ref = GetTexture(client_id);
if (!texture_ref) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2D", "unknown texture");
return;
}
TextureMetadata* texture_metadata = GetTextureMetadata(client_id);
if (!texture_metadata) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2D", "unknown texture");
return;
}
Texture* texture = texture_ref->texture();
if (texture->IsImmutable()) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glTexStorage2D",
"texture is immutable");
return;
}
if (levels == 0) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2D", "levels == 0");
return;
}
if (width < 1 || height < 1) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2D", "dimensions < 1");
return;
}
// For testing only. Allows us to stress the ability to respond to OOM errors.
if (workarounds().simulate_out_of_memory_on_large_textures &&
(width * height >= 4096 * 4096)) {
LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glTexStorage2D",
"synthetic out of memory");
return;
}
// Check if we have enough memory.
unsigned int internal_format =
viz::GLInternalFormat(texture_metadata->format());
bool is_compressed_format =
viz::IsResourceFormatCompressed(texture_metadata->format());
GLenum format =
TextureManager::ExtractFormatFromStorageFormat(internal_format);
GLenum type = TextureManager::ExtractTypeFromStorageFormat(internal_format);
GLsizei level_width = width;
GLsizei level_height = height;
base::CheckedNumeric<uint32_t> estimated_size(0);
PixelStoreParams params;
params.alignment = 1;
for (int ii = 0; ii < levels; ++ii) {
uint32_t size;
if (is_compressed_format) {
DCHECK_EQ(static_cast<unsigned int>(GL_ETC1_RGB8_OES), internal_format);
base::CheckedNumeric<uint32_t> bytes_required(0);
const int kS3TCBlockWidth = 4;
const int kS3TCBlockHeight = 4;
const int kS3TCDXT1BlockSize = 8;
bytes_required = (width + kS3TCBlockWidth - 1) / kS3TCBlockWidth;
bytes_required *= (height + kS3TCBlockHeight - 1) / kS3TCBlockHeight;
bytes_required *= kS3TCDXT1BlockSize;
if (!bytes_required.IsValid()) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2D", "invalid size");
return;
}
size = bytes_required.ValueOrDefault(0);
} else {
if (!GLES2Util::ComputeImageDataSizesES3(
level_width, level_height, 1 /* level_depth */, format, type,
params, &size, nullptr, nullptr, nullptr, nullptr)) {
LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glTexStorage2D",
"dimensions too large");
return;
}
}
estimated_size += size;
level_width = std::max(1, level_width >> 1);
level_height = std::max(1, level_height >> 1);
}
if (!estimated_size.IsValid() ||
!EnsureGPUMemoryAvailable(estimated_size.ValueOrDefault(0))) {
LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glTexStorage2D", "out of memory");
return;
}
if (texture_metadata->use_buffer()) {
if (!GetCapabilities().texture_storage_image) {
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2DImage", "use_buffer");
return;
}
DCHECK(levels == 1);
TexStorage2DImage(texture_ref, *texture_metadata, width, height);
} else if (GetCapabilities().texture_storage) {
TexStorage2D(texture_ref, *texture_metadata, levels, width, height);
} else {
// TODO(backer): Support more than one texture level.
DCHECK(levels == 1);
TexImage2D(texture_ref, *texture_metadata, width, height);
}
texture->SetImmutable(true);
}
// Include the auto-generated part of this file. We split this because it means
// we can easily edit the non-auto generated parts right here in this file
// instead of having to edit some template or the code generator.
#include "base/macros.h"
#include "gpu/command_buffer/service/raster_decoder_autogen.h"
} // namespace raster
} // namespace gpu