Index: gpu/gles2_conform_support/egl/display.cc |
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc |
index f12c94257376c4a3298655a9b4ca082964b98902..b4e01587fd4144d0272380f49a9b153802849211 100644 |
--- a/gpu/gles2_conform_support/egl/display.cc |
+++ b/gpu/gles2_conform_support/egl/display.cc |
@@ -4,134 +4,115 @@ |
#include "gpu/gles2_conform_support/egl/display.h" |
-#include <stddef.h> |
-#include <stdint.h> |
- |
-#include <vector> |
-#include "base/at_exit.h" |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/command_line.h" |
-#include "base/lazy_instance.h" |
-#include "gpu/command_buffer/client/gles2_implementation.h" |
-#include "gpu/command_buffer/client/gles2_lib.h" |
-#include "gpu/command_buffer/client/shared_memory_limits.h" |
-#include "gpu/command_buffer/client/transfer_buffer.h" |
-#include "gpu/command_buffer/service/context_group.h" |
-#include "gpu/command_buffer/service/mailbox_manager.h" |
-#include "gpu/command_buffer/service/memory_tracking.h" |
-#include "gpu/command_buffer/service/transfer_buffer_manager.h" |
#include "gpu/gles2_conform_support/egl/config.h" |
+#include "gpu/gles2_conform_support/egl/context.h" |
#include "gpu/gles2_conform_support/egl/surface.h" |
-#include "gpu/gles2_conform_support/egl/test_support.h" |
- |
-namespace { |
-const int32_t kCommandBufferSize = 1024 * 1024; |
-const int32_t kTransferBufferSize = 512 * 1024; |
-} |
+#include "gpu/gles2_conform_support/egl/thread_state.h" |
namespace egl { |
-#if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY) |
-// egl::Display is used for comformance tests and command_buffer_gles. We only |
-// need the exit manager for the command_buffer_gles library. |
-// TODO(hendrikw): Find a cleaner solution for this. |
-namespace { |
-base::LazyInstance<base::Lock>::Leaky g_exit_manager_lock; |
-int g_exit_manager_use_count; |
-base::AtExitManager* g_exit_manager; |
-void RefAtExitManager() { |
- base::AutoLock lock(g_exit_manager_lock.Get()); |
-#if defined(COMPONENT_BUILD) |
- if (g_command_buffer_gles_has_atexit_manager) { |
- return; |
- } |
-#endif |
- if (g_exit_manager_use_count == 0) { |
- g_exit_manager = new base::AtExitManager; |
- } |
- ++g_exit_manager_use_count; |
-} |
-void ReleaseAtExitManager() { |
- base::AutoLock lock(g_exit_manager_lock.Get()); |
-#if defined(COMPONENT_BUILD) |
- if (g_command_buffer_gles_has_atexit_manager) { |
- return; |
- } |
-#endif |
- --g_exit_manager_use_count; |
- if (g_exit_manager_use_count == 0) { |
- delete g_exit_manager; |
- g_exit_manager = nullptr; |
- } |
-} |
-} |
-#endif |
- |
-Display::Display(EGLNativeDisplayType display_id) |
- : display_id_(display_id), |
- gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()), |
- is_initialized_(false), |
- create_offscreen_(false), |
- create_offscreen_width_(0), |
- create_offscreen_height_(0), |
- next_fence_sync_release_(1) { |
-#if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY) |
- RefAtExitManager(); |
-#endif |
+ |
+Display::Display() |
+ : is_initialized_(false), |
+ next_create_window_surface_creates_pbuffer_(false), |
+ window_surface_pbuffer_width_(0), |
+ window_surface_pbuffer_height_(0) { |
} |
Display::~Display() { |
- gles2::Terminate(); |
-#if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY) |
- ReleaseAtExitManager(); |
-#endif |
+ surfaces_.clear(); |
+ contexts_.clear(); |
} |
- |
-bool Display::Initialize() { |
- gles2::Initialize(); |
- is_initialized_ = true; |
- return true; |
+void Display::SetNextCreateWindowSurfaceCreatesPBuffer(EGLint width, |
+ EGLint height) { |
+ next_create_window_surface_creates_pbuffer_ = true; |
+ window_surface_pbuffer_width_ = width; |
+ window_surface_pbuffer_height_ = height; |
} |
-bool Display::IsValidConfig(EGLConfig config) { |
- return (config != NULL) && (config == config_.get()); |
-} |
+EGLBoolean Display::Initialize(ThreadState* ts, EGLint* major, EGLint* minor) { |
+ base::AutoLock auto_lock(lock_); |
+ is_initialized_ = true; |
-bool Display::ChooseConfigs(EGLConfig* configs, |
- EGLint config_size, |
- EGLint* num_config) { |
- // TODO(alokp): Find out a way to find all configs. CommandBuffer currently |
- // does not support finding or choosing configs. |
- *num_config = 1; |
- if (configs != NULL) { |
- if (config_ == NULL) { |
- config_.reset(new Config); |
- } |
- configs[0] = config_.get(); |
+ if (major) |
+ *major = 1; |
+ if (minor) |
+ *minor = 4; |
+ return ts->ReturnSuccess(EGL_TRUE); |
+} |
+ |
+EGLBoolean Display::Terminate(ThreadState* ts) { |
+ base::AutoLock auto_lock(lock_); |
+ is_initialized_ = false; |
+ surfaces_.clear(); |
+ for (const auto& context : contexts_) |
+ context->MarkDestroyed(); |
+ contexts_.clear(); |
+ return ts->ReturnSuccess(EGL_TRUE); |
+} |
+ |
+const char* Display::QueryString(ThreadState* ts, EGLint name) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError<const char*>(EGL_NOT_INITIALIZED, nullptr); |
+ switch (name) { |
+ case EGL_CLIENT_APIS: |
+ return ts->ReturnSuccess("OpenGL_ES"); |
+ case EGL_EXTENSIONS: |
+ return ts->ReturnSuccess(""); |
+ case EGL_VENDOR: |
+ return ts->ReturnSuccess("Google Inc."); |
+ case EGL_VERSION: |
+ return ts->ReturnSuccess("1.4"); |
+ default: |
+ return ts->ReturnError<const char*>(EGL_BAD_PARAMETER, nullptr); |
} |
- return true; |
} |
-bool Display::GetConfigs(EGLConfig* configs, |
- EGLint config_size, |
- EGLint* num_config) { |
- // TODO(alokp): Find out a way to find all configs. CommandBuffer currently |
- // does not support finding or choosing configs. |
- *num_config = 1; |
- if (configs != NULL) { |
- if (config_ == NULL) { |
- config_.reset(new Config); |
+EGLBoolean Display::ChooseConfig(ThreadState* ts, |
+ const EGLint* attrib_list, |
+ EGLConfig* configs, |
+ EGLint config_size, |
+ EGLint* num_config) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); |
+ if (num_config == nullptr) |
+ return ts->ReturnError(EGL_BAD_PARAMETER, EGL_FALSE); |
+ if (!Config::ValidateAttributeList(attrib_list)) |
+ return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
+ InitializeConfigsIfNeeded(); |
+ if (!configs) |
+ config_size = 0; |
+ *num_config = 0; |
+ for (size_t i = 0; i < arraysize(configs_); ++i) { |
+ if (configs_[i]->Matches(attrib_list)) { |
+ if (*num_config < config_size) { |
+ configs[*num_config] = configs_[i].get(); |
+ } |
+ ++*num_config; |
} |
- configs[0] = config_.get(); |
} |
- return true; |
-} |
- |
-bool Display::GetConfigAttrib(EGLConfig config, |
- EGLint attribute, |
- EGLint* value) { |
- const egl::Config* cfg = static_cast<egl::Config*>(config); |
- return cfg->GetAttrib(attribute, value); |
+ return ts->ReturnSuccess(EGL_TRUE); |
+} |
+ |
+EGLBoolean Display::GetConfigs(ThreadState* ts, |
+ EGLConfig* configs, |
+ EGLint config_size, |
+ EGLint* num_config) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); |
+ if (num_config == nullptr) |
+ return ts->ReturnError(EGL_BAD_PARAMETER, EGL_FALSE); |
+ InitializeConfigsIfNeeded(); |
+ if (!configs) |
+ config_size = 0; |
+ *num_config = arraysize(configs_); |
+ size_t count = |
+ std::min(arraysize(configs_), static_cast<size_t>(config_size)); |
+ for (size_t i = 0; i < count; ++i) |
+ configs[i] = configs_[i].get(); |
+ return ts->ReturnSuccess(EGL_TRUE); |
} |
bool Display::IsValidNativeWindow(EGLNativeWindowType win) { |
@@ -143,241 +124,233 @@ bool Display::IsValidNativeWindow(EGLNativeWindowType win) { |
#endif // OS_WIN |
} |
-bool Display::IsValidSurface(EGLSurface surface) { |
- return (surface != NULL) && (surface == surface_.get()); |
+EGLBoolean Display::GetConfigAttrib(ThreadState* ts, |
+ EGLConfig cfg, |
+ EGLint attribute, |
+ EGLint* value) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); |
+ const egl::Config* config = GetConfig(cfg); |
+ if (!config) |
+ return ts->ReturnError(EGL_BAD_CONFIG, EGL_FALSE); |
+ if (!config->GetAttrib(attribute, value)) |
+ return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
+ return ts->ReturnSuccess(EGL_TRUE); |
+} |
+ |
+EGLSurface Display::CreatePbufferSurface(ThreadState* ts, |
+ EGLConfig cfg, |
+ const EGLint* attrib_list) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_SURFACE); |
+ const egl::Config* config = GetConfig(cfg); |
+ if (!config) |
+ return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE); |
+ EGLint value = EGL_NONE; |
+ config->GetAttrib(EGL_SURFACE_TYPE, &value); |
+ if ((value & EGL_PBUFFER_BIT) == 0) |
+ return ts->ReturnError(EGL_BAD_MATCH, EGL_NO_SURFACE); |
+ if (!egl::Surface::ValidatePbufferAttributeList(attrib_list)) |
+ return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); |
+ |
+ int width = 1; |
+ int height = 1; |
+ if (attrib_list) { |
+ for (const int32_t* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) { |
+ switch (attr[0]) { |
+ case EGL_WIDTH: |
+ width = attr[1]; |
+ break; |
+ case EGL_HEIGHT: |
+ height = attr[1]; |
+ break; |
+ } |
+ } |
+ } |
+ return DoCreatePbufferSurface(ts, config, width, height); |
+} |
+ |
+EGLSurface Display::DoCreatePbufferSurface(ThreadState* ts, |
+ const Config* config, |
+ EGLint width, |
+ EGLint height) { |
+ lock_.AssertAcquired(); |
+ scoped_refptr<gfx::GLSurface> gl_surface; |
+ gl_surface = |
+ gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(width, height)); |
+ if (!gl_surface) |
+ return ts->ReturnError(EGL_BAD_ALLOC, nullptr); |
+ surfaces_.emplace_back(new Surface(gl_surface.get(), config)); |
+ return ts->ReturnSuccess<EGLSurface>(surfaces_.back().get()); |
} |
-EGLSurface Display::CreateWindowSurface(EGLConfig config, |
+EGLSurface Display::CreateWindowSurface(ThreadState* ts, |
+ EGLConfig cfg, |
EGLNativeWindowType win, |
const EGLint* attrib_list) { |
- if (surface_ != NULL) { |
- // We do not support more than one window surface. |
- return EGL_NO_SURFACE; |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_SURFACE); |
+ const egl::Config* config = GetConfig(cfg); |
+ if (!config) |
+ return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE); |
+ EGLint value = EGL_NONE; |
+ config->GetAttrib(EGL_SURFACE_TYPE, &value); |
+ if ((value & EGL_WINDOW_BIT) == 0) |
+ return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE); |
+ if (!next_create_window_surface_creates_pbuffer_ && !IsValidNativeWindow(win)) |
+ return ts->ReturnError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); |
+ if (!Surface::ValidateWindowAttributeList(attrib_list)) |
+ return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); |
+ if (next_create_window_surface_creates_pbuffer_) { |
+ EGLSurface result = DoCreatePbufferSurface(ts, config, |
+ window_surface_pbuffer_width_, |
+ window_surface_pbuffer_height_); |
+ next_create_window_surface_creates_pbuffer_ = false; |
+ window_surface_pbuffer_width_ = 0; |
+ window_surface_pbuffer_height_ = 0; |
+ return result; |
} |
- |
- { |
- gpu::TransferBufferManager* manager = |
- new gpu::TransferBufferManager(nullptr); |
- transfer_buffer_manager_ = manager; |
- manager->Initialize(); |
- } |
- std::unique_ptr<gpu::CommandBufferService> command_buffer( |
- new gpu::CommandBufferService(transfer_buffer_manager_.get())); |
- |
- scoped_refptr<gpu::gles2::FeatureInfo> feature_info( |
- new gpu::gles2::FeatureInfo(gpu_driver_bug_workarounds_)); |
- scoped_refptr<gpu::gles2::ContextGroup> group(new gpu::gles2::ContextGroup( |
- gpu_preferences_, NULL, NULL, |
- new gpu::gles2::ShaderTranslatorCache(gpu_preferences_), |
- new gpu::gles2::FramebufferCompletenessCache, feature_info, true)); |
- |
- decoder_.reset(gpu::gles2::GLES2Decoder::Create(group.get())); |
- if (!decoder_.get()) |
- return EGL_NO_SURFACE; |
- |
- executor_.reset( |
- new gpu::CommandExecutor(command_buffer.get(), decoder_.get(), NULL)); |
- |
- decoder_->set_engine(executor_.get()); |
- gfx::Size size(create_offscreen_width_, create_offscreen_height_); |
- if (create_offscreen_) { |
- gl_surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size); |
- create_offscreen_ = false; |
- create_offscreen_width_ = 0; |
- create_offscreen_height_ = 0; |
- } else { |
- gl_surface_ = gfx::GLSurface::CreateViewGLSurface(win); |
- } |
- if (!gl_surface_.get()) |
- return EGL_NO_SURFACE; |
- |
- gl_context_ = gfx::GLContext::CreateGLContext(NULL, |
- gl_surface_.get(), |
- gfx::PreferDiscreteGpu); |
- if (!gl_context_.get()) |
- return EGL_NO_SURFACE; |
- |
- gl_context_->MakeCurrent(gl_surface_.get()); |
- |
- EGLint depth_size = 0; |
- EGLint alpha_size = 0; |
- EGLint stencil_size = 0; |
- GetConfigAttrib(config, EGL_DEPTH_SIZE, &depth_size); |
- GetConfigAttrib(config, EGL_ALPHA_SIZE, &alpha_size); |
- GetConfigAttrib(config, EGL_STENCIL_SIZE, &stencil_size); |
- std::vector<int32_t> attribs; |
- attribs.push_back(EGL_DEPTH_SIZE); |
- attribs.push_back(depth_size); |
- attribs.push_back(EGL_ALPHA_SIZE); |
- attribs.push_back(alpha_size); |
- attribs.push_back(EGL_STENCIL_SIZE); |
- attribs.push_back(stencil_size); |
- // TODO(gman): Insert attrib_list. Although ES 1.1 says it must be null |
- attribs.push_back(EGL_NONE); |
- |
- if (!decoder_->Initialize(gl_surface_.get(), |
- gl_context_.get(), |
- gl_surface_->IsOffscreen(), |
- size, |
- gpu::gles2::DisallowedFeatures(), |
- attribs)) { |
- return EGL_NO_SURFACE; |
+ scoped_refptr<gfx::GLSurface> gl_surface; |
+ gl_surface = gfx::GLSurface::CreateViewGLSurface(win); |
+ if (!gl_surface) |
+ return ts->ReturnError(EGL_BAD_ALLOC, EGL_NO_SURFACE); |
+ surfaces_.emplace_back(new Surface(gl_surface.get(), config)); |
+ return ts->ReturnSuccess(surfaces_.back().get()); |
+} |
+ |
+EGLBoolean Display::DestroySurface(ThreadState* ts, EGLSurface sfe) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); |
+ auto it = std::find(surfaces_.begin(), surfaces_.end(), sfe); |
+ if (it == surfaces_.end()) |
+ return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); |
+ surfaces_.erase(it); |
+ return ts->ReturnSuccess(EGL_TRUE); |
+} |
+ |
+EGLBoolean Display::ReleaseCurrent(ThreadState* ts) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnSuccess(EGL_TRUE); |
+ ThreadState::AutoCurrentContextRestore accr(ts); |
+ if (ts->current_context()) { |
+ Context::MakeCurrent(ts->current_context(), ts->current_surface(), nullptr, |
+ nullptr); |
+ accr.SetCurrent(nullptr, nullptr); |
} |
- |
- command_buffer->SetPutOffsetChangeCallback(base::Bind( |
- &gpu::CommandExecutor::PutChanged, base::Unretained(executor_.get()))); |
- command_buffer->SetGetBufferChangeCallback(base::Bind( |
- &gpu::CommandExecutor::SetGetBuffer, base::Unretained(executor_.get()))); |
- |
- std::unique_ptr<gpu::gles2::GLES2CmdHelper> cmd_helper( |
- new gpu::gles2::GLES2CmdHelper(command_buffer.get())); |
- if (!cmd_helper->Initialize(kCommandBufferSize)) |
- return NULL; |
- |
- std::unique_ptr<gpu::TransferBuffer> transfer_buffer( |
- new gpu::TransferBuffer(cmd_helper.get())); |
- |
- command_buffer_.reset(command_buffer.release()); |
- transfer_buffer_.reset(transfer_buffer.release()); |
- gles2_cmd_helper_.reset(cmd_helper.release()); |
- surface_.reset(new Surface(win)); |
- |
- return surface_.get(); |
-} |
- |
-void Display::DestroySurface(EGLSurface surface) { |
- DCHECK(IsValidSurface(surface)); |
- executor_.reset(); |
- if (decoder_.get()) { |
- decoder_->Destroy(true); |
- } |
- decoder_.reset(); |
- gl_surface_ = NULL; |
- gl_context_ = NULL; |
- surface_.reset(); |
-} |
- |
-void Display::SwapBuffers(EGLSurface surface) { |
- DCHECK(IsValidSurface(surface)); |
- context_->SwapBuffers(); |
-} |
- |
-bool Display::IsValidContext(EGLContext ctx) { |
- return (ctx != NULL) && (ctx == context_.get()); |
-} |
- |
-EGLContext Display::CreateContext(EGLConfig config, |
+ return ts->ReturnSuccess(EGL_TRUE); |
+} |
+ |
+EGLBoolean Display::MakeCurrent(ThreadState* ts, |
+ EGLSurface draw, |
+ EGLSurface read, |
+ EGLSurface ctx) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); |
+ ThreadState::AutoCurrentContextRestore accr(ts); |
+ // Client might have called use because it changed some other gl binding |
+ // global state. For example, the client might have called eglMakeCurrent on |
+ // the same EGL as what command buffer uses. The client probably knows that |
+ // this invalidates the internal state of command buffer, too. So reset the |
+ // current context with accr in any case, regardless whether context or |
+ // surface pointer changes. |
+ Surface* new_surface = GetSurface(draw); |
+ if (!new_surface) |
+ return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); |
+ new_surface = GetSurface(read); |
+ if (!new_surface) |
+ return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); |
+ egl::Context* new_context = GetContext(ctx); |
+ if (!new_context) |
+ return ts->ReturnError(EGL_BAD_CONTEXT, EGL_FALSE); |
+ if (draw != read) |
+ return ts->ReturnError(EGL_BAD_MATCH, EGL_FALSE); |
+ |
+ Surface* current_surface = ts->current_surface(); |
+ Context* current_context = ts->current_context(); |
+ |
+ if (current_context != new_context && |
+ new_context->is_current_in_some_thread()) |
+ return ts->ReturnError(EGL_BAD_ACCESS, EGL_FALSE); |
+ |
+ if (current_surface != new_surface && |
+ new_surface->is_current_in_some_thread()) |
+ return ts->ReturnError(EGL_BAD_ACCESS, EGL_FALSE); |
+ |
+ if (!Context::MakeCurrent(current_context, |
+ current_context ? current_surface : nullptr, |
+ new_context, new_context ? new_surface : nullptr)) |
+ return ts->ReturnError(EGL_BAD_MATCH, EGL_FALSE); |
+ |
+ accr.SetCurrent(new_surface, new_context); |
+ return ts->ReturnSuccess(EGL_TRUE); |
+} |
+ |
+EGLBoolean Display::SwapBuffers(ThreadState* ts, EGLSurface sfe) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); |
+ egl::Surface* surface = GetSurface(sfe); |
+ if (!surface) |
+ return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); |
+ if (ts->current_surface() != surface) |
+ return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); |
+ if (!ts->current_context()->SwapBuffers(surface)) |
+ ts->ReturnError(EGL_CONTEXT_LOST, EGL_FALSE); |
+ return ts->ReturnSuccess(EGL_TRUE); |
+} |
+ |
+EGLContext Display::CreateContext(ThreadState* ts, |
+ EGLConfig cfg, |
EGLContext share_ctx, |
const EGLint* attrib_list) { |
- DCHECK(IsValidConfig(config)); |
- // TODO(alokp): Add support for shared contexts. |
- if (share_ctx != NULL) |
- return EGL_NO_CONTEXT; |
- |
- DCHECK(command_buffer_ != NULL); |
- DCHECK(transfer_buffer_.get()); |
- |
- bool bind_generates_resources = true; |
- bool lose_context_when_out_of_memory = false; |
- bool support_client_side_arrays = true; |
- |
- context_.reset( |
- new gpu::gles2::GLES2Implementation(gles2_cmd_helper_.get(), |
- NULL, |
- transfer_buffer_.get(), |
- bind_generates_resources, |
- lose_context_when_out_of_memory, |
- support_client_side_arrays, |
- this)); |
- |
- if (!context_->Initialize(kTransferBufferSize, kTransferBufferSize / 2, |
- kTransferBufferSize * 2, |
- gpu::SharedMemoryLimits::kNoLimit)) { |
- return EGL_NO_CONTEXT; |
- } |
- |
- context_->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets"); |
- context_->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs"); |
- |
- return context_.get(); |
-} |
- |
-void Display::DestroyContext(EGLContext ctx) { |
- DCHECK(IsValidContext(ctx)); |
- context_.reset(); |
- transfer_buffer_.reset(); |
-} |
- |
-bool Display::MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx) { |
- if (ctx == EGL_NO_CONTEXT) { |
- gles2::SetGLContext(NULL); |
- } else { |
- DCHECK(IsValidSurface(draw)); |
- DCHECK(IsValidSurface(read)); |
- DCHECK(IsValidContext(ctx)); |
- gles2::SetGLContext(context_.get()); |
- gl_context_->MakeCurrent(gl_surface_.get()); |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_CONTEXT); |
+ if (share_ctx != EGL_NO_CONTEXT) { |
+ egl::Context* share_context = GetContext(share_ctx); |
+ if (!share_context) |
+ return ts->ReturnError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); |
+ // TODO(alokp): Add support for shared contexts. |
+ return ts->ReturnError(EGL_BAD_MATCH, EGL_NO_CONTEXT); |
} |
- return true; |
-} |
- |
-void Display::SetGpuControlClient(gpu::GpuControlClient*) { |
- // The client is not currently called, so don't store it. |
-} |
- |
-gpu::Capabilities Display::GetCapabilities() { |
- return decoder_->GetCapabilities(); |
-} |
- |
-int32_t Display::CreateImage(ClientBuffer buffer, |
- size_t width, |
- size_t height, |
- unsigned internalformat) { |
- NOTIMPLEMENTED(); |
- return -1; |
-} |
- |
-void Display::DestroyImage(int32_t id) { |
- NOTIMPLEMENTED(); |
-} |
- |
-int32_t Display::CreateGpuMemoryBufferImage(size_t width, |
- size_t height, |
- unsigned internalformat, |
- unsigned usage) { |
- NOTIMPLEMENTED(); |
- return -1; |
-} |
- |
-void Display::SignalQuery(uint32_t query, const base::Closure& callback) { |
- NOTIMPLEMENTED(); |
-} |
-void Display::SetLock(base::Lock*) { |
- NOTIMPLEMENTED(); |
-} |
- |
-void Display::EnsureWorkVisible() { |
- // This is only relevant for out-of-process command buffers. |
-} |
- |
-gpu::CommandBufferNamespace Display::GetNamespaceID() const { |
- return gpu::CommandBufferNamespace::IN_PROCESS; |
-} |
- |
-gpu::CommandBufferId Display::GetCommandBufferID() const { |
- return gpu::CommandBufferId(); |
-} |
- |
-int32_t Display::GetExtraCommandBufferData() const { |
- return 0; |
+ if (!egl::Context::ValidateAttributeList(attrib_list)) |
+ return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
+ const egl::Config* config = GetConfig(cfg); |
+ if (!config) |
+ return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_CONTEXT); |
+ scoped_refptr<Context> context(new Context(this, config)); |
+ if (!context) |
+ return ts->ReturnError(EGL_BAD_ALLOC, EGL_NO_CONTEXT); |
+ contexts_.emplace_back(context.get()); |
+ return ts->ReturnSuccess<EGLContext>(context.get()); |
+} |
+ |
+EGLBoolean Display::DestroyContext(ThreadState* ts, EGLContext ctx) { |
+ base::AutoLock auto_lock(lock_); |
+ if (!is_initialized_) |
+ return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); |
+ auto it = std::find(contexts_.begin(), contexts_.end(), ctx); |
+ if (it == contexts_.end()) |
+ return ts->ReturnError(EGL_BAD_CONTEXT, EGL_FALSE); |
+ (*it)->MarkDestroyed(); |
+ contexts_.erase(it); |
+ return ts->ReturnSuccess(EGL_TRUE); |
} |
uint64_t Display::GenerateFenceSyncRelease() { |
+ base::AutoLock auto_lock(lock_); |
return next_fence_sync_release_++; |
} |
bool Display::IsFenceSyncRelease(uint64_t release) { |
+ base::AutoLock auto_lock(lock_); |
return release > 0 && release < next_fence_sync_release_; |
} |
@@ -389,13 +362,41 @@ bool Display::IsFenceSyncFlushReceived(uint64_t release) { |
return IsFenceSyncRelease(release); |
} |
-void Display::SignalSyncToken(const gpu::SyncToken& sync_token, |
- const base::Closure& callback) { |
- NOTIMPLEMENTED(); |
+void Display::InitializeConfigsIfNeeded() { |
+ lock_.AssertAcquired(); |
+ if (!configs_[0]) { |
+ // The interface offers separate configs for window and pbuffer. |
+ // This way we can record the client intention at context creation time. |
+ // The GL implementation (gfx::GLContext and gfx::GLSurface) needs this |
+ // distinction when creating a context. |
+ configs_[0].reset(new Config(EGL_WINDOW_BIT)); |
+ configs_[1].reset(new Config(EGL_PBUFFER_BIT)); |
+ } |
+} |
+ |
+const Config* Display::GetConfig(EGLConfig cfg) { |
+ lock_.AssertAcquired(); |
+ for (const auto& config : configs_) { |
+ if (config.get() == cfg) |
+ return config.get(); |
+ } |
+ return nullptr; |
+} |
+ |
+Surface* Display::GetSurface(EGLSurface surface) { |
+ lock_.AssertAcquired(); |
+ auto it = std::find(surfaces_.begin(), surfaces_.end(), surface); |
+ if (it == surfaces_.end()) |
+ return nullptr; |
+ return it->get(); |
} |
-bool Display::CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) { |
- return false; |
+Context* Display::GetContext(EGLContext context) { |
+ lock_.AssertAcquired(); |
+ auto it = std::find(contexts_.begin(), contexts_.end(), context); |
+ if (it == contexts_.end()) |
+ return nullptr; |
+ return it->get(); |
} |
} // namespace egl |