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"
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"
27 #if defined COMPOSITOR_2
32 class TextureGL
: public Texture
{
34 TextureGL(CompositorGL
* compositor
);
37 virtual void SetBitmap(const SkBitmap
& bitmap
,
38 const gfx::Point
& origin
,
39 const gfx::Size
& overall_size
) OVERRIDE
;
42 virtual void Draw(const ui::Transform
& transform
) OVERRIDE
;
45 unsigned int texture_id_
;
47 CompositorGL
* compositor_
;
48 DISALLOW_COPY_AND_ASSIGN(TextureGL
);
51 class CompositorGL
: public Compositor
{
53 explicit CompositorGL(gfx::AcceleratedWidget widget
);
54 virtual ~CompositorGL();
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_
;
69 // Keep track of whether compositing has started or not.
72 DISALLOW_COPY_AND_ASSIGN(CompositorGL
);
75 TextureGL::TextureGL(CompositorGL
* compositor
) : texture_id_(0),
76 compositor_(compositor
) {
79 TextureGL::~TextureGL() {
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();
96 // Texture needs to be created. We assume the first call is for
97 // a full-sized canvas.
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();
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()) {
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.
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);
188 if (!t
.matrix().isIdentity()) {
192 glDisable(GL_TEXTURE_2D
);
195 CompositorGL::CompositorGL(gfx::AcceleratedWidget widget
)
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);
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);
222 void CompositorGL::NotifyStart() {
224 gl_context_
->MakeCurrent();
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() {
238 gl_context_
->SwapBuffers();
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
);
261 class CompositorGL
: public Compositor
{
263 explicit CompositorGL(gfx::AcceleratedWidget widget
);
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.
280 DISALLOW_COPY_AND_ASSIGN(CompositorGL
);
283 CompositorGL::CompositorGL(gfx::AcceleratedWidget widget
)
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() {
292 gl_context_
->MakeCurrent();
295 void CompositorGL::NotifyEnd() {
297 gl_context_
->SwapBuffers();
301 void CompositorGL::DrawTextureWithTransform(TextureID txt
,
302 const ui::Transform
& transform
) {
309 void CompositorGL::SaveTransform() {
314 void CompositorGL::RestoreTransform() {
320 Compositor
* Compositor::Create(gfx::AcceleratedWidget widget
) {
321 if (gfx::GetGLImplementation() != gfx::kGLImplementationNone
)
322 return new CompositorGL(widget
);