blob: c69ed50e06e6b70e961b6fc26c7472530b8e4ba5 [file] [log] [blame]
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COBALT_RENDERER_BACKEND_EGL_GRAPHICS_CONTEXT_H_
#define COBALT_RENDERER_BACKEND_EGL_GRAPHICS_CONTEXT_H_
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/renderer/backend/egl/render_target.h"
#include "cobalt/renderer/backend/egl/resource_context.h"
#include "cobalt/renderer/backend/egl/texture.h"
#include "cobalt/renderer/backend/egl/texture_data.h"
#include "cobalt/renderer/backend/graphics_context.h"
namespace cobalt {
namespace renderer {
namespace backend {
class GraphicsSystemEGL;
// Encapsulates a context created via EGL, which implies that it makes
// accessible the OpenGL ES API.
class GraphicsContextEGL : public GraphicsContext {
public:
GraphicsContextEGL(GraphicsSystem* parent_system, EGLDisplay display,
EGLConfig config, ResourceContext* resource_context);
~GraphicsContextEGL() OVERRIDE;
GraphicsSystemEGL* system_egl();
scoped_ptr<TextureEGL> CreateTexture(scoped_ptr<TextureDataEGL> texture_data);
scoped_ptr<TextureEGL> CreateTextureFromRawMemory(
const scoped_refptr<ConstRawTextureMemoryEGL>& raw_texture_memory,
intptr_t offset, const math::Size& size, GLenum format,
int pitch_in_bytes);
scoped_refptr<RenderTarget> CreateOffscreenRenderTarget(
const math::Size& dimensions) OVERRIDE;
scoped_array<uint8_t> DownloadPixelDataAsRGBA(
const scoped_refptr<RenderTarget>& render_target) OVERRIDE;
void Finish() OVERRIDE;
// Helper class to allow one to create a RAII object that will acquire the
// current context upon construction and release it upon destruction.
class ScopedMakeCurrent {
public:
explicit ScopedMakeCurrent(GraphicsContextEGL* graphics_context)
: graphics_context_(graphics_context),
was_current_(graphics_context_->is_current_),
previous_current_surface_(graphics_context_->current_surface_) {
graphics_context_->MakeCurrent();
}
ScopedMakeCurrent(GraphicsContextEGL* graphics_context,
RenderTargetEGL* surface)
: graphics_context_(graphics_context),
was_current_(graphics_context_->is_current_),
previous_current_surface_(graphics_context_->current_surface_) {
graphics_context_->MakeCurrentWithSurface(surface);
}
~ScopedMakeCurrent() {
if (was_current_) {
graphics_context_->MakeCurrentWithSurface(previous_current_surface_);
} else {
graphics_context_->ReleaseCurrentContext();
}
}
private:
GraphicsContextEGL* graphics_context_;
bool was_current_;
RenderTargetEGL* previous_current_surface_;
};
// Helper methods to make this context current and associate it with
// a surface. In EGL, a context is either not current or it is current and
// associated with a surface. For all functionality (e.g. texture creation)
// that is provided but does not require a surface binding, null_surface_ is
// specified as a surface.
void MakeCurrentWithSurface(RenderTargetEGL* surface);
// Alternatively, this call can be made to make the context current along
// with a null surface. You would be interested in this method if you don't
// plan to be making any draw calls, such as if you're setting up a texture.
void MakeCurrent();
void ReleaseCurrentContext();
void SwapBuffers(RenderTargetEGL* surface);
void Blit(GLuint texture, int x, int y, int width, int height);
bool ReadPixelsNeedVerticalFlip() {
if (!read_pixels_needs_vertical_flip_) {
read_pixels_needs_vertical_flip_ = ComputeReadPixelsNeedVerticalFlip();
}
return *read_pixels_needs_vertical_flip_;
}
private:
// Performs a test to determine if the pixel data returned by glReadPixels
// needs to be vertically flipped or not. This test is expensive and so
// it should be only done once and the results cached.
bool ComputeReadPixelsNeedVerticalFlip();
// Sets up all structures (like Shaders and vertex buffers) required to
// support the Frame::BlitToRenderTarget() functionality.
void SetupBlitObjects();
// Clear render target. For security reasons, we clear the display buffer
// before rendering to it for the first 3 swaps. This way if the application
// does not fill the frame (presumably by accident), this clear color will
// appear and not data that was left in the buffer from a previous process
// that could be a security risk. This is meant to act as a layer of
// security, other layers are 1) The graphics driver should not let our
// process access data from other processes in the first place and 2) The
// application should completely cover the screen when it is rendered.
void SecurityClear();
EGLDisplay display_;
// The EGL/OpenGL ES context hosted by this GraphicsContextEGL object.
EGLContext context_;
EGLConfig config_;
// Keep track of whether this context has been set to current or not, and
// if so what surface was associated with it.
bool is_current_;
scoped_refptr<RenderTargetEGL> current_surface_;
// A dummy surface that is made current when we wish to execute OpenGL ES
// commands that don't actually involve a surface in any way (e.g. texture
// creation).
scoped_refptr<RenderTargetEGL> null_surface_;
// Cache whether or not BGRA texture format is supported by the underlying
// OpenGL ES implementation.
bool bgra_format_supported_;
// Data required to provide BlitToRenderTarget() functionality via OpenGL ES.
GLuint blit_vertex_shader_;
GLuint blit_fragment_shader_;
static const int kBlitPositionAttribute = 0;
static const int kBlitTexcoordAttribute = 1;
GLuint blit_program_;
GLuint blit_vertex_buffer_;
// Lazily evaluate whether we need to do a vertical flip when calling
// glReadPixels(), and cache the result here when that question is answered.
base::optional<bool> read_pixels_needs_vertical_flip_;
// When creating and destroying textures, OpenGL calls need to be made with
// a GL context current. By making TextureEGL a friend class of
// GraphicsContextEGL, the tight relationship and association of a TextureEGL
// with a GraphicsContextEGL is made more explicit, and it also allows
// TextureEGL to access MakeCurrent()/ReleaseCurrentContext() methods
// of GraphicsContextEGL.
friend class TextureEGL;
};
} // namespace backend
} // namespace renderer
} // namespace cobalt
#endif // COBALT_RENDERER_BACKEND_EGL_GRAPHICS_CONTEXT_H_