blob: c3b62f10d7d2edfea66ad318ab5c2fba9d22fd4f [file] [log] [blame]
// Copyright (c) 2010 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/pgl/pgl.h"
#include "build/build_config.h"
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "gpu/command_buffer/client/gles2_lib.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/thread_local.h"
#include "gpu/pgl/command_buffer_pepper.h"
namespace {
const int32 kTransferBufferSize = 512 * 1024;
class PGLContextImpl {
public:
PGLContextImpl(NPP npp,
NPDevice* device,
NPDeviceContext3D* device_context);
~PGLContextImpl();
// Initlaize a PGL context with a transfer buffer of a particular size.
PGLBoolean Initialize(int32 transfer_buffer_size);
// Destroy all resources associated with the PGL context.
void Destroy();
// Make a PGL context current for the calling thread.
static PGLBoolean MakeCurrent(PGLContextImpl* pgl_context);
// Display all content rendered since last call to SwapBuffers.
PGLBoolean SwapBuffers();
// Get the current error code.
PGLInt GetError();
private:
PGLContextImpl(const PGLContextImpl&);
void operator=(const PGLContextImpl&);
NPP npp_;
NPDevice* device_;
NPDeviceContext3D* device_context_;
CommandBufferPepper* command_buffer_;
gpu::gles2::GLES2CmdHelper* gles2_helper_;
int32 transfer_buffer_id_;
gpu::gles2::GLES2Implementation* gles2_implementation_;
};
gpu::ThreadLocalKey g_pgl_context_key;
bool g_pgl_context_key_allocated = false;
PGLContextImpl::PGLContextImpl(NPP npp,
NPDevice* device,
NPDeviceContext3D* device_context)
: npp_(npp),
device_(device),
device_context_(device_context),
command_buffer_(NULL),
gles2_helper_(NULL),
transfer_buffer_id_(0),
gles2_implementation_(NULL) {
}
PGLContextImpl::~PGLContextImpl() {
Destroy();
}
PGLBoolean PGLContextImpl::Initialize(int32 transfer_buffer_size) {
// Create and initialize the objects required to issue GLES2 calls.
command_buffer_ = new CommandBufferPepper(
npp_, device_, device_context_);
gles2_helper_ = new gpu::gles2::GLES2CmdHelper(command_buffer_);
gpu::Buffer buffer = command_buffer_->GetRingBuffer();
if (gles2_helper_->Initialize(buffer.size)) {
transfer_buffer_id_ =
command_buffer_->CreateTransferBuffer(kTransferBufferSize);
gpu::Buffer transfer_buffer =
command_buffer_->GetTransferBuffer(transfer_buffer_id_);
if (transfer_buffer.ptr) {
gles2_implementation_ = new gpu::gles2::GLES2Implementation(
gles2_helper_,
transfer_buffer.size,
transfer_buffer.ptr,
transfer_buffer_id_,
false);
return PGL_TRUE;
}
}
// Tear everything down if initialization failed.
Destroy();
return PGL_FALSE;
}
void PGLContextImpl::Destroy() {
delete gles2_implementation_;
gles2_implementation_ = NULL;
if (command_buffer_ && transfer_buffer_id_ != 0) {
command_buffer_->DestroyTransferBuffer(transfer_buffer_id_);
transfer_buffer_id_ = 0;
}
delete gles2_helper_;
gles2_helper_ = NULL;
delete command_buffer_;
command_buffer_ = NULL;
}
PGLBoolean PGLContextImpl::MakeCurrent(PGLContextImpl* pgl_context) {
if (!g_pgl_context_key_allocated)
return PGL_FALSE;
gpu::ThreadLocalSetValue(g_pgl_context_key, pgl_context);
if (pgl_context) {
gles2::SetGLContext(pgl_context->gles2_implementation_);
// Don't request latest error status from service. Just use the locally
// cached information from the last flush.
// TODO(apatrick): I'm not sure if this should actually change the
// current context if it fails. For now it gets changed even if it fails
// becuase making GL calls with a NULL context crashes.
#if defined(ENABLE_NEW_NPDEVICE_API)
if (pgl_context->command_buffer_->GetCachedError() != gpu::error::kNoError)
return PGL_FALSE;
#else
if (pgl_context->device_context_->error != NPDeviceContext3DError_NoError)
return PGL_FALSE;
#endif
} else {
gles2::SetGLContext(NULL);
}
return PGL_TRUE;
}
PGLBoolean PGLContextImpl::SwapBuffers() {
// Don't request latest error status from service. Just use the locally cached
// information from the last flush.
#if defined(ENABLE_NEW_NPDEVICE_API)
if (command_buffer_->GetCachedError() != gpu::error::kNoError)
return PGL_FALSE;
#else
if (device_context_->error != NPDeviceContext3DError_NoError)
return PGL_FALSE;
#endif
gles2_implementation_->SwapBuffers();
return PGL_TRUE;
}
PGLInt PGLContextImpl::GetError() {
gpu::CommandBuffer::State state = command_buffer_->GetState();
if (state.error == gpu::error::kNoError) {
return PGL_SUCCESS;
} else {
// All command buffer errors are unrecoverable. The error is treated as a
// lost context: destroy the context and create another one.
return PGL_CONTEXT_LOST;
}
}
} // namespace anonymous
extern "C" {
PGLBoolean pglInitialize() {
if (g_pgl_context_key_allocated)
return PGL_TRUE;
gles2::Initialize();
g_pgl_context_key = gpu::ThreadLocalAlloc();
g_pgl_context_key_allocated = true;
return PGL_TRUE;
}
PGLBoolean pglTerminate() {
if (!g_pgl_context_key_allocated)
return PGL_TRUE;
gpu::ThreadLocalFree(g_pgl_context_key);
g_pgl_context_key_allocated = false;
g_pgl_context_key = 0;
gles2::Terminate();
return PGL_TRUE;
}
PGLContext pglCreateContext(NPP npp,
NPDevice* device,
NPDeviceContext3D* device_context) {
if (!g_pgl_context_key_allocated)
return NULL;
PGLContextImpl* pgl_context = new PGLContextImpl(
npp, device, device_context);
if (pgl_context->Initialize(kTransferBufferSize)) {
return pgl_context;
}
delete pgl_context;
return NULL;
}
PGLBoolean pglMakeCurrent(PGLContext pgl_context) {
return PGLContextImpl::MakeCurrent(static_cast<PGLContextImpl*>(pgl_context));
}
PGLContext pglGetCurrentContext(void) {
if (!g_pgl_context_key_allocated)
return NULL;
return static_cast<PGLContext>(gpu::ThreadLocalGetValue(g_pgl_context_key));
}
PGLBoolean pglSwapBuffers(void) {
PGLContextImpl* context = static_cast<PGLContextImpl*>(
pglGetCurrentContext());
if (!context)
return PGL_FALSE;
return context->SwapBuffers();
}
PGLBoolean pglDestroyContext(PGLContext pgl_context) {
if (!g_pgl_context_key_allocated)
return PGL_FALSE;
if (!pgl_context)
return PGL_FALSE;
if (pgl_context == pglGetCurrentContext())
pglMakeCurrent(PGL_NO_CONTEXT);
delete static_cast<PGLContextImpl*>(pgl_context);
return PGL_TRUE;
}
PGLInt pglGetError() {
if (!g_pgl_context_key)
return PGL_NOT_INITIALIZED;
PGLContextImpl* context = static_cast<PGLContextImpl*>(
pglGetCurrentContext());
if (!context)
return PGL_BAD_CONTEXT;
return context->GetError();
}
} // extern "C"