| 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 |