OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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. | |
4 | |
5 #include "chrome/gpu/gpu_backing_store_glx.h" | |
6 | |
7 #include "app/gfx/gl/gl_bindings.h" | |
8 #include "app/surface/transport_dib.h" | |
9 #include "base/scoped_ptr.h" | |
10 #include "chrome/common/gpu_messages.h" | |
11 #include "chrome/gpu/gpu_backing_store_glx_context.h" | |
12 #include "chrome/gpu/gpu_thread.h" | |
13 #include "chrome/gpu/gpu_view_x.h" | |
14 #include "gfx/rect.h" | |
15 #include "skia/ext/platform_canvas.h" | |
16 #include "third_party/skia/include/core/SkBitmap.h" | |
17 | |
18 GpuBackingStoreGLX::GpuBackingStoreGLX(GpuViewX* view, | |
19 GpuThread* gpu_thread, | |
20 int32 routing_id, | |
21 const gfx::Size& size) | |
22 : view_(view), | |
23 gpu_thread_(gpu_thread), | |
24 routing_id_(routing_id), | |
25 size_(size), | |
26 texture_id_(0) { | |
27 gpu_thread_->AddRoute(routing_id_, this); | |
28 | |
29 view_->BindContext(); // Must do this before issuing OpenGl. | |
30 | |
31 glGenTextures(1, &texture_id_); | |
32 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
33 | |
34 // TODO(apatrick): This function are not available in GLES2. | |
35 // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
36 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
37 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
38 } | |
39 | |
40 GpuBackingStoreGLX::~GpuBackingStoreGLX() { | |
41 if (texture_id_) | |
42 glDeleteTextures(1, &texture_id_); | |
43 gpu_thread_->RemoveRoute(routing_id_); | |
44 } | |
45 | |
46 void GpuBackingStoreGLX::OnMessageReceived(const IPC::Message& msg) { | |
47 IPC_BEGIN_MESSAGE_MAP(GpuBackingStoreGLX, msg) | |
48 IPC_MESSAGE_HANDLER(GpuMsg_PaintToBackingStore, OnPaintToBackingStore) | |
49 IPC_MESSAGE_HANDLER(GpuMsg_ScrollBackingStore, OnScrollBackingStore) | |
50 IPC_END_MESSAGE_MAP_EX() | |
51 } | |
52 | |
53 void GpuBackingStoreGLX::OnChannelConnected(int32 peer_pid) { | |
54 } | |
55 | |
56 void GpuBackingStoreGLX::OnChannelError() { | |
57 // FIXME(brettw) does this mean we aren't getting any more messages and we | |
58 // should delete outselves? | |
59 NOTIMPLEMENTED(); | |
60 } | |
61 | |
62 void GpuBackingStoreGLX::OnPaintToBackingStore( | |
63 base::ProcessId source_process_id, | |
64 TransportDIB::Id id, | |
65 const gfx::Rect& bitmap_rect, | |
66 const std::vector<gfx::Rect>& copy_rects) { | |
67 scoped_ptr<TransportDIB> dib(TransportDIB::Map(id)); | |
68 view_->BindContext(); | |
69 | |
70 scoped_ptr<skia::PlatformCanvas> canvas( | |
71 dib->GetPlatformCanvas(bitmap_rect.width(), bitmap_rect.height())); | |
72 const SkBitmap& transport_bitmap = | |
73 canvas->getTopPlatformDevice().accessBitmap(false); | |
74 | |
75 for (size_t i = 0; i < copy_rects.size(); i++) | |
76 PaintOneRectToBackingStore(transport_bitmap, bitmap_rect, copy_rects[i]); | |
77 | |
78 gpu_thread_->Send(new GpuHostMsg_PaintToBackingStore_ACK(routing_id_)); | |
79 | |
80 view_->Repaint(); | |
81 } | |
82 | |
83 void GpuBackingStoreGLX::OnScrollBackingStore(int dx, int dy, | |
84 const gfx::Rect& clip_rect, | |
85 const gfx::Size& view_size) { | |
86 // Create a framebuffer to render our scrolled texture into. | |
87 GpuBackingStoreGLXContext* context = view_->gpu_thread()->GetGLXContext(); | |
88 if (!context->BindTextureForScrolling(view_->window(), size_)) | |
89 return; | |
90 | |
91 glEnable(GL_TEXTURE_2D); | |
92 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
93 | |
94 // Set up the the tranform so we can paint exact pixels to the screen, with | |
95 // (0, 0) at the bottom left. | |
96 // TODO(apatrick): Commenting out because these variables were only used by | |
97 // code that is now commented out. | |
98 // float w = static_cast<float>(size_.width()); | |
99 // float h = static_cast<float>(size_.height()); | |
100 glViewport(0, 0, size_.width(), size_.height()); | |
101 | |
102 // TODO(apatrick): These functions are not available in GLES2. | |
103 // glLoadIdentity(); | |
104 // glOrtho(0.0, w, 0.0, h, -1.0, 1.0); | |
105 | |
106 // Paint the non-scrolled background of the page. Note that we try to avoid | |
107 // this if the entire thing is scrolling, which is a common case. | |
108 if (view_size != clip_rect.size()) { | |
109 // TODO(apatrick): These functions are not available in GLES2. | |
110 // glBegin(GL_QUADS); | |
111 // glTexCoord2f(0.0f, 0.0f); | |
112 // glVertex2f(0.0, 0.0); | |
113 | |
114 // glTexCoord2f(0.0f, 1.0f); | |
115 // glVertex2f(0.0, h); | |
116 | |
117 // glTexCoord2f(1.0f, 1.0f); | |
118 // glVertex2f(w, h); | |
119 | |
120 // glTexCoord2f(1.0f, 0.0f); | |
121 // glVertex2f(w, 0.0); | |
122 // glEnd(); | |
123 } | |
124 | |
125 // Constrain the painting to only the area we're scrolling. Compute the clip | |
126 // rect in OpenGL pixel coords, which uses the lower-left as the origin. | |
127 gfx::Rect gl_clip_rect(clip_rect.x(), clip_rect.y(), | |
128 clip_rect.width(), clip_rect.height()); | |
129 | |
130 glEnable(GL_SCISSOR_TEST); | |
131 glScissor(gl_clip_rect.x(), gl_clip_rect.y(), | |
132 gl_clip_rect.width(), gl_clip_rect.height()); | |
133 | |
134 // Paint the offset texture. | |
135 // TODO(apatrick): These functions are not available in GLES2. | |
136 // glTranslatef(static_cast<float>(dx), static_cast<float>(dy), 0.0f); | |
137 // glBegin(GL_QUADS); | |
138 // glTexCoord2f(0.0f, 0.0f); | |
139 // glVertex2f(0.0, 0.0); | |
140 | |
141 // glTexCoord2f(0.0f, 1.0f); | |
142 // glVertex2f(0.0, h); | |
143 | |
144 // glTexCoord2f(1.0f, 1.0f); | |
145 // glVertex2f(w, h); | |
146 | |
147 // glTexCoord2f(1.0f, 0.0f); | |
148 // glVertex2f(w, 0.0); | |
149 // glEnd(); | |
150 glDisable(GL_SCISSOR_TEST); | |
151 | |
152 glBindTexture(GL_TEXTURE_2D, 0); | |
153 texture_id_ = context->SwapTextureForScrolling(texture_id_, size_); | |
154 glFlush(); | |
155 DCHECK(texture_id_); | |
156 } | |
157 | |
158 void GpuBackingStoreGLX::PaintOneRectToBackingStore( | |
159 const SkBitmap& transport_bitmap, | |
160 const gfx::Rect& bitmap_rect, | |
161 const gfx::Rect& copy_rect) { | |
162 // Make a bitmap referring to the correct subset of the input bitmap. | |
163 SkBitmap copy_bitmap; | |
164 if (copy_rect.x() == 0 && | |
165 copy_rect.y() == 0 && | |
166 copy_rect.width() == bitmap_rect.width() && | |
167 copy_rect.height() == bitmap_rect.height()) { | |
168 // The subregion we're being asked to copy is the full bitmap. We don't | |
169 // have to do any extra work to make the bitmap, we can just refer to the | |
170 // original data (bitmap assignments are just refs to the original). | |
171 copy_bitmap = transport_bitmap; | |
172 } else { | |
173 // Make a rect referring to the subset into the original (copy_rect and | |
174 // bitmap_rect are both in global coords) and make a copy of that data to | |
175 // give to OpenGL later. | |
176 // | |
177 // TODO(brettw) on desktop GL (not ES) we can do a trick here using | |
178 // GL_UNPACK_ROW_WIDTH, GL_UNPACK_SKIP_PIXELS and GL_UNPACK_SKIP_ROWS to | |
179 // avoid this copy. | |
180 // | |
181 // On ES, it may be better to actually call subimage for each row of | |
182 // the updated bitmap to avoid the copy. We will have to benchmark that | |
183 // approach against making the copy here to see if it performs better on | |
184 // the systems we're targeting. | |
185 SkIRect sk_copy_rect = { copy_rect.x() - bitmap_rect.x(), | |
186 copy_rect.y() - bitmap_rect.y(), | |
187 copy_rect.right() - bitmap_rect.x(), | |
188 copy_rect.bottom() - bitmap_rect.y()}; | |
189 | |
190 // extractSubset will not acutually make a copy, and Skia will refer to the | |
191 // original data which is not what we want, since rows won't be contiguous. | |
192 // However, since this is very cheap, we can do it and *then* make a copy. | |
193 SkBitmap non_copied_subset; | |
194 transport_bitmap.extractSubset(&non_copied_subset, sk_copy_rect); | |
195 non_copied_subset.copyTo(©_bitmap, SkBitmap::kARGB_8888_Config); | |
196 CHECK(!copy_bitmap.isNull()); | |
197 } | |
198 | |
199 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
200 | |
201 SkAutoLockPixels lock(copy_bitmap); | |
202 if (copy_rect.size() == size_ && copy_rect.size() != texture_size_) { | |
203 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, copy_rect.width(), | |
204 copy_rect.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, | |
205 copy_bitmap.getAddr32(0, 0)); | |
206 texture_size_ = copy_rect.size(); | |
207 } else { | |
208 /* Debugging code for why the below call may fail. | |
209 int existing_width = 0, existing_height = 0; | |
210 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, | |
211 &existing_width); | |
212 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, | |
213 &existing_height); | |
214 */ | |
215 glTexSubImage2D(GL_TEXTURE_2D, 0, copy_rect.x(), copy_rect.y(), | |
216 copy_rect.width(), copy_rect.height(), | |
217 GL_BGRA, GL_UNSIGNED_BYTE, | |
218 copy_bitmap.getAddr32(0, 0)); | |
219 /* Enable if you're having problems with TexSubImage failing. | |
220 int err = glGetError(); | |
221 DCHECK(err == GL_NO_ERROR) << "Error " << err << | |
222 " copying (" << copy_rect.x() << "," << copy_rect.y() << | |
223 ")," << copy_rect.width() << "x" << copy_rect.height() << | |
224 " for bitmap " << texture_size_.width() << "x" << | |
225 texture_size_.height() << | |
226 " real size " << existing_width << "x" << existing_height << | |
227 " for " << this; | |
228 */ | |
229 } | |
230 } | |
OLD | NEW |