Compositor GL + basic views support.
[chromium-blink-merge.git] / ui / gfx / compositor / compositor_gl.cc
blobd952f9bcfd992ec4a9c4e1127fddc510d6225e4d
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gfx/compositor/compositor.h"
7 #include <GL/gl.h>
9 #include "base/basictypes.h"
10 #include "base/compiler_specific.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "third_party/skia/include/core/SkBitmap.h"
15 #include "third_party/skia/include/core/SkMatrix.h"
16 #include "third_party/skia/include/core/SkScalar.h"
17 #include "ui/gfx/rect.h"
18 #include "ui/gfx/transform.h"
19 #include "ui/gfx/gl/gl_bindings.h"
20 #include "ui/gfx/gl/gl_context.h"
21 #include "ui/gfx/gl/gl_implementation.h"
22 #include "ui/gfx/gl/gl_surface.h"
23 #include "ui/gfx/gl/gl_surface_glx.h"
25 namespace ui {
27 #if defined COMPOSITOR_2
28 namespace glHidden {
30 class CompositorGL;
32 class TextureGL : public Texture {
33 public:
34 TextureGL(CompositorGL* compositor);
35 virtual ~TextureGL();
37 virtual void SetBitmap(const SkBitmap& bitmap,
38 const gfx::Point& origin,
39 const gfx::Size& overall_size) OVERRIDE;
41 // Draws the texture.
42 virtual void Draw(const ui::Transform& transform) OVERRIDE;
44 private:
45 unsigned int texture_id_;
46 gfx::Size size_;
47 CompositorGL* compositor_;
48 DISALLOW_COPY_AND_ASSIGN(TextureGL);
51 class CompositorGL : public Compositor {
52 public:
53 explicit CompositorGL(gfx::AcceleratedWidget widget);
54 virtual ~CompositorGL();
56 void MakeCurrent();
57 gfx::Size GetSize();
59 private:
60 // Overridden from Compositor.
61 virtual Texture* CreateTexture() OVERRIDE;
62 virtual void NotifyStart() OVERRIDE;
63 virtual void NotifyEnd() OVERRIDE;
65 // The GL context used for compositing.
66 scoped_ptr<gfx::GLContext> gl_context_;
67 gfx::Size size_;
69 // Keep track of whether compositing has started or not.
70 bool started_;
72 DISALLOW_COPY_AND_ASSIGN(CompositorGL);
75 TextureGL::TextureGL(CompositorGL* compositor) : texture_id_(0),
76 compositor_(compositor) {
79 TextureGL::~TextureGL() {
80 if (texture_id_) {
81 compositor_->MakeCurrent();
82 glDeleteTextures(1, &texture_id_);
86 void TextureGL::SetBitmap(const SkBitmap& bitmap,
87 const gfx::Point& origin,
88 const gfx::Size& overall_size) {
89 // Verify bitmap pixels are contiguous.
90 DCHECK_EQ(bitmap.rowBytes(),
91 SkBitmap::ComputeRowBytes(bitmap.config(), bitmap.width()));
92 SkAutoLockPixels lock (bitmap);
93 void* pixels = bitmap.getPixels();
95 if (!texture_id_) {
96 // Texture needs to be created. We assume the first call is for
97 // a full-sized canvas.
98 size_ = overall_size;
100 glGenTextures(1, &texture_id_);
101 glBindTexture(GL_TEXTURE_2D, texture_id_);
102 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
103 size_.width(), size_.height(), 0,
104 GL_RGBA, GL_UNSIGNED_BYTE, pixels);
106 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
107 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
109 // Map ARGB -> RGBA, remembering the we are transferring using
110 // GL_UNSIGNED_BYTE transfer, so endian-ness comes into play.
111 // TODO(wjmaclean) Verify this will work with eglImage.
112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R_EXT, GL_BLUE);
113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B_EXT, GL_RED);
115 } else if (size_ != overall_size) { // Size has changed.
116 size_ = overall_size;
117 glBindTexture(GL_TEXTURE_2D, texture_id_);
118 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
119 size_.width(), size_.height(), 0,
120 GL_RGBA, GL_UNSIGNED_BYTE, pixels);
121 } else { // Uploading partial texture.
122 glBindTexture(GL_TEXTURE_2D, texture_id_);
123 glTexSubImage2D(GL_TEXTURE_2D, 0, origin.x(), origin.y(),
124 bitmap.width(), bitmap.height(),
125 GL_RGBA, GL_UNSIGNED_BYTE, pixels);
129 void TextureGL::Draw(const ui::Transform& transform) {
130 gfx::Size window_size = compositor_->GetSize();
132 ui::Transform t;
133 t.ConcatTranslate(1,1);
134 t.ConcatScale(size_.width()/2.0f, size_.height()/2.0f);
135 t.ConcatTranslate(0, -size_.height());
136 t.ConcatScale(1, -1);
138 t.ConcatTransform(transform); // Add view transform.
140 t.ConcatTranslate(0, -window_size.height());
141 t.ConcatScale(1, -1);
142 t.ConcatTranslate(-window_size.width()/2.0f, -window_size.height()/2.0f);
143 t.ConcatScale(2.0f/window_size.width(), 2.0f/window_size.height());
145 glEnable(GL_TEXTURE_2D);
146 glBindTexture(GL_TEXTURE_2D, texture_id_);
148 if (!t.matrix().isIdentity()) {
149 float m[16];
150 const SkMatrix& matrix = t.matrix(); // *mat;
152 // Convert 3x3 view transform matrix (row major) into 4x4 GL matrix (column
153 // major). Assume 2-D rotations/translations restricted to XY plane.
155 m[ 0] = matrix[0];
156 m[ 1] = matrix[3];
157 m[ 2] = 0;
158 m[ 3] = matrix[6];
160 m[ 4] = matrix[1];
161 m[ 5] = matrix[4];
162 m[ 6] = 0;
163 m[ 7] = matrix[7];
165 m[ 8] = 0;
166 m[ 9] = 0;
167 m[10] = 1;
168 m[11] = 0;
170 m[12] = matrix[2];
171 m[13] = matrix[5];
172 m[14] = 0;
173 m[15] = matrix[8];
175 glLoadMatrixf(m);
176 } else {
177 glLoadIdentity();
180 glBegin(GL_QUADS);
181 glColor4f(1.0, 1.0, 1.0, 1.0);
182 glTexCoord2d(0.0, 1.0); glVertex2d(-1, -1);
183 glTexCoord2d(1.0, 1.0); glVertex2d( 1, -1);
184 glTexCoord2d(1.0, 0.0); glVertex2d( 1, 1);
185 glTexCoord2d(0.0, 0.0); glVertex2d(-1, 1);
186 glEnd();
188 if (!t.matrix().isIdentity()) {
189 glLoadIdentity();
192 glDisable(GL_TEXTURE_2D);
195 CompositorGL::CompositorGL(gfx::AcceleratedWidget widget)
196 : started_(false) {
197 scoped_ptr<gfx::GLSurface> surface(
198 gfx::GLSurface::CreateViewGLSurface(widget));
199 gl_context_.reset(gfx::GLContext::CreateGLContext(surface.release(), NULL)),
200 gl_context_->MakeCurrent();
201 glColorMask(true, true, true, true);
202 glEnable(GL_BLEND);
203 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
206 CompositorGL::~CompositorGL() {
209 void CompositorGL::MakeCurrent() {
210 gl_context_->MakeCurrent();
213 gfx::Size CompositorGL::GetSize() {
214 return gl_context_->GetSize();
217 Texture* CompositorGL::CreateTexture() {
218 Texture* texture = new TextureGL(this);
219 return texture;
222 void CompositorGL::NotifyStart() {
223 started_ = true;
224 gl_context_->MakeCurrent();
225 glViewport(0, 0,
226 gl_context_->GetSize().width(), gl_context_->GetSize().height());
228 // Clear to 'psychedelic' purple to make it easy to spot un-rendered regions.
229 glClearColor(223.0 / 255, 0, 1, 1);
230 glColorMask(true, true, true, true);
231 glClear(GL_COLOR_BUFFER_BIT);
232 // Disable alpha writes, since we're using blending anyways.
233 glColorMask(true, true, true, false);
236 void CompositorGL::NotifyEnd() {
237 DCHECK(started_);
238 gl_context_->SwapBuffers();
239 started_ = false;
242 } // namespace
244 // static
245 Compositor* Compositor::Create(gfx::AcceleratedWidget widget) {
246 // The following line of code exists soley to disable IO restrictions
247 // on this thread long enough to perform the GL bindings.
248 // TODO(backer) Remove this when GL initialisation cleaned up.
249 base::ThreadRestrictions::ScopedAllowIO allow_io;
250 // TODO(backer) Remove this when GL thread patch lands. Should be init'd
251 // by the new GPU thread.
252 // http://codereview.chromium.org/6677055/
253 gfx::InitializeGLBindings(gfx::kGLImplementationDesktopGL);
254 gfx::GLSurfaceGLX::InitializeOneOff();
256 if (gfx::GetGLImplementation() != gfx::kGLImplementationNone)
257 return new glHidden::CompositorGL(widget);
258 return NULL;
260 #else
261 class CompositorGL : public Compositor {
262 public:
263 explicit CompositorGL(gfx::AcceleratedWidget widget);
265 private:
266 // Overridden from Compositor.
267 void NotifyStart() OVERRIDE;
268 void NotifyEnd() OVERRIDE;
269 void DrawTextureWithTransform(TextureID txt,
270 const ui::Transform& transform) OVERRIDE;
271 void SaveTransform() OVERRIDE;
272 void RestoreTransform() OVERRIDE;
274 // The GL context used for compositing.
275 scoped_ptr<gfx::GLContext> gl_context_;
277 // Keep track of whether compositing has started or not.
278 bool started_;
280 DISALLOW_COPY_AND_ASSIGN(CompositorGL);
283 CompositorGL::CompositorGL(gfx::AcceleratedWidget widget)
284 : started_(false) {
285 scoped_ptr<gfx::GLSurface> surface(
286 gfx::GLSurface::CreateViewGLSurface(widget));
287 gl_context_.reset(gfx::GLContext::CreateGLContext(surface.release(), NULL));
290 void CompositorGL::NotifyStart() {
291 started_ = true;
292 gl_context_->MakeCurrent();
295 void CompositorGL::NotifyEnd() {
296 DCHECK(started_);
297 gl_context_->SwapBuffers();
298 started_ = false;
301 void CompositorGL::DrawTextureWithTransform(TextureID txt,
302 const ui::Transform& transform) {
303 DCHECK(started_);
305 // TODO(wjmaclean):
306 NOTIMPLEMENTED();
309 void CompositorGL::SaveTransform() {
310 // TODO(sadrul):
311 NOTIMPLEMENTED();
314 void CompositorGL::RestoreTransform() {
315 // TODO(sadrul):
316 NOTIMPLEMENTED();
319 // static
320 Compositor* Compositor::Create(gfx::AcceleratedWidget widget) {
321 if (gfx::GetGLImplementation() != gfx::kGLImplementationNone)
322 return new CompositorGL(widget);
323 return NULL;
325 #endif
327 } // namespace ui