| 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/browser/renderer_host/accelerated_surface_container_mac.h" | |
| 6 | |
| 7 #include "app/surface/io_surface_support_mac.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "chrome/browser/renderer_host/accelerated_surface_container_manager_mac
.h" | |
| 10 #include "webkit/plugins/npapi/webplugin.h" | |
| 11 | |
| 12 AcceleratedSurfaceContainerMac::AcceleratedSurfaceContainerMac( | |
| 13 AcceleratedSurfaceContainerManagerMac* manager, | |
| 14 bool opaque) | |
| 15 : manager_(manager), | |
| 16 opaque_(opaque), | |
| 17 surface_id_(0), | |
| 18 width_(0), | |
| 19 height_(0), | |
| 20 texture_(0), | |
| 21 texture_needs_upload_(true), | |
| 22 texture_pending_deletion_(0), | |
| 23 visible_(false), | |
| 24 was_painted_to_(false) { | |
| 25 } | |
| 26 | |
| 27 AcceleratedSurfaceContainerMac::~AcceleratedSurfaceContainerMac() { | |
| 28 } | |
| 29 | |
| 30 void AcceleratedSurfaceContainerMac::SetSizeAndIOSurface( | |
| 31 int32 width, | |
| 32 int32 height, | |
| 33 uint64 io_surface_identifier) { | |
| 34 // Ignore |io_surface_identifier|: The surface hasn't been painted to and | |
| 35 // only contains garbage data. Update the surface in |set_was_painted_to()| | |
| 36 // instead. | |
| 37 width_ = width; | |
| 38 height_ = height; | |
| 39 } | |
| 40 | |
| 41 void AcceleratedSurfaceContainerMac::SetSizeAndTransportDIB( | |
| 42 int32 width, | |
| 43 int32 height, | |
| 44 TransportDIB::Handle transport_dib) { | |
| 45 if (TransportDIB::is_valid(transport_dib)) { | |
| 46 transport_dib_.reset(TransportDIB::Map(transport_dib)); | |
| 47 EnqueueTextureForDeletion(); | |
| 48 width_ = width; | |
| 49 height_ = height; | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 void AcceleratedSurfaceContainerMac::SetGeometry( | |
| 54 const webkit::npapi::WebPluginGeometry& geom) { | |
| 55 visible_ = geom.visible; | |
| 56 if (geom.rects_valid) | |
| 57 clip_rect_ = geom.clip_rect; | |
| 58 } | |
| 59 | |
| 60 void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) { | |
| 61 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); | |
| 62 GLenum target = GL_TEXTURE_RECTANGLE_ARB; | |
| 63 if (texture_pending_deletion_) { | |
| 64 // Clean up an old texture object. This is essentially a pre-emptive | |
| 65 // cleanup, as the resources will be released when the OpenGL context | |
| 66 // associated with our containing NSView is destroyed. However, if we | |
| 67 // resize a plugin often, we might generate a lot of textures, so we | |
| 68 // should try to eagerly reclaim their resources. Note also that the | |
| 69 // OpenGL context must be current when performing the deletion, and it | |
| 70 // seems risky to make the OpenGL context current at an arbitrary point | |
| 71 // in time, which is why the deletion does not occur in the container's | |
| 72 // destructor. | |
| 73 glDeleteTextures(1, &texture_pending_deletion_); | |
| 74 texture_pending_deletion_ = 0; | |
| 75 } | |
| 76 if (!texture_) { | |
| 77 if ((io_surface_support && !surface_.get()) || | |
| 78 (!io_surface_support && !transport_dib_.get())) | |
| 79 return; | |
| 80 glGenTextures(1, &texture_); | |
| 81 glBindTexture(target, texture_); | |
| 82 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| 83 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| 84 if (io_surface_support) { | |
| 85 texture_needs_upload_ = true; | |
| 86 } else { | |
| 87 // Reserve space on the card for the actual texture upload, done with the | |
| 88 // glTexSubImage2D() call, below. | |
| 89 glTexImage2D(target, | |
| 90 0, // mipmap level 0 | |
| 91 GL_RGBA, // internal format | |
| 92 width_, | |
| 93 height_, | |
| 94 0, // no border | |
| 95 GL_BGRA, // The GPU plugin read BGRA pixels | |
| 96 GL_UNSIGNED_INT_8_8_8_8_REV, | |
| 97 NULL); // No data, this call just reserves room. | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 // When using an IOSurface, the texture does not need to be repeatedly | |
| 102 // uploaded, just when we've been told we have to. | |
| 103 if (io_surface_support && texture_needs_upload_) { | |
| 104 DCHECK(surface_.get()); | |
| 105 glBindTexture(target, texture_); | |
| 106 // Don't think we need to identify a plane. | |
| 107 GLuint plane = 0; | |
| 108 io_surface_support->CGLTexImageIOSurface2D(context, | |
| 109 target, | |
| 110 GL_RGBA, | |
| 111 surface_width_, | |
| 112 surface_height_, | |
| 113 GL_BGRA, | |
| 114 GL_UNSIGNED_INT_8_8_8_8_REV, | |
| 115 surface_.get(), | |
| 116 plane); | |
| 117 texture_needs_upload_ = false; | |
| 118 } | |
| 119 // If using TransportDIBs, the texture needs to be uploaded every frame. | |
| 120 if (transport_dib_.get() != NULL) { | |
| 121 void* pixel_memory = transport_dib_->memory(); | |
| 122 if (pixel_memory) { | |
| 123 glBindTexture(target, texture_); | |
| 124 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Needed for NPOT textures. | |
| 125 glTexSubImage2D(target, | |
| 126 0, // mipmap level 0 | |
| 127 0, // x-offset | |
| 128 0, // y-offset | |
| 129 width_, | |
| 130 height_, | |
| 131 GL_BGRA, // The GPU plugin gave us BGRA pixels | |
| 132 GL_UNSIGNED_INT_8_8_8_8_REV, | |
| 133 pixel_memory); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 if (texture_) { | |
| 138 int texture_width = io_surface_support ? surface_width_ : width_; | |
| 139 int texture_height = io_surface_support ? surface_height_ : height_; | |
| 140 | |
| 141 // TODO(kbr): convert this to use only OpenGL ES 2.0 functionality. | |
| 142 | |
| 143 // TODO(kbr): may need to pay attention to cutout rects. | |
| 144 int clipX = clip_rect_.x(); | |
| 145 int clipY = clip_rect_.y(); | |
| 146 int clipWidth = clip_rect_.width(); | |
| 147 int clipHeight = clip_rect_.height(); | |
| 148 | |
| 149 if (clipX + clipWidth > texture_width) | |
| 150 clipWidth = texture_width - clipX; | |
| 151 if (clipY + clipHeight > texture_height) | |
| 152 clipHeight = texture_height - clipY; | |
| 153 | |
| 154 if (opaque_) { | |
| 155 // Pepper 3D's output is currently considered opaque even if the | |
| 156 // program draws pixels with alpha less than 1. In order to have | |
| 157 // this effect, we need to drop the alpha channel of the input, | |
| 158 // replacing it with alpha = 1. | |
| 159 | |
| 160 // First fill the rectangle with alpha=1. | |
| 161 glColorMask(false, false, false, true); | |
| 162 glColor4f(0.0f, 0.0f, 0.0f, 1.0f); | |
| 163 glBegin(GL_TRIANGLE_STRIP); | |
| 164 glVertex3f(0, 0, 0); | |
| 165 glVertex3f(clipWidth, 0, 0); | |
| 166 glVertex3f(0, clipHeight, 0); | |
| 167 glVertex3f(clipWidth, clipHeight, 0); | |
| 168 glEnd(); | |
| 169 | |
| 170 // Now draw the color channels from the incoming texture. | |
| 171 glColorMask(true, true, true, false); | |
| 172 // This call shouldn't be necessary -- we are using the GL_REPLACE | |
| 173 // texture environment mode -- but it appears to be. | |
| 174 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
| 175 } else { | |
| 176 glColorMask(true, true, true, true); | |
| 177 } | |
| 178 | |
| 179 // Draw the color channels from the incoming texture. | |
| 180 glBindTexture(target, texture_); | |
| 181 glEnable(target); | |
| 182 glBegin(GL_TRIANGLE_STRIP); | |
| 183 | |
| 184 glTexCoord2f(clipX, texture_height - clipY); | |
| 185 glVertex3f(0, 0, 0); | |
| 186 | |
| 187 glTexCoord2f(clipX + clipWidth, texture_height - clipY); | |
| 188 glVertex3f(clipWidth, 0, 0); | |
| 189 | |
| 190 glTexCoord2f(clipX, texture_height - clipY - clipHeight); | |
| 191 glVertex3f(0, clipHeight, 0); | |
| 192 | |
| 193 glTexCoord2f(clipX + clipWidth, texture_height - clipY - clipHeight); | |
| 194 glVertex3f(clipWidth, clipHeight, 0); | |
| 195 | |
| 196 glEnd(); | |
| 197 glDisable(target); | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 bool AcceleratedSurfaceContainerMac::ShouldBeVisible() const { | |
| 202 return visible_ && was_painted_to_ && !clip_rect_.IsEmpty(); | |
| 203 } | |
| 204 | |
| 205 void AcceleratedSurfaceContainerMac::set_was_painted_to(uint64 surface_id) { | |
| 206 if (surface_id && (!surface_ || surface_id != surface_id_)) { | |
| 207 // Keep the surface that was most recently painted to around. | |
| 208 if (IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize()) { | |
| 209 CFTypeRef surface = io_surface_support->IOSurfaceLookup( | |
| 210 static_cast<uint32>(surface_id)); | |
| 211 // Can fail if IOSurface with that ID was already released by the | |
| 212 // gpu process or the plugin process. We will get a |set_was_painted_to()| | |
| 213 // message with a new surface soon in that case. | |
| 214 if (surface) { | |
| 215 surface_.reset(surface); | |
| 216 surface_id_ = surface_id; | |
| 217 surface_width_ = io_surface_support->IOSurfaceGetWidth(surface_); | |
| 218 surface_height_ = io_surface_support->IOSurfaceGetHeight(surface_); | |
| 219 EnqueueTextureForDeletion(); | |
| 220 } | |
| 221 } | |
| 222 } | |
| 223 was_painted_to_ = true; | |
| 224 } | |
| 225 | |
| 226 void AcceleratedSurfaceContainerMac::EnqueueTextureForDeletion() { | |
| 227 if (texture_) { | |
| 228 DCHECK(texture_pending_deletion_ == 0); | |
| 229 texture_pending_deletion_ = texture_; | |
| 230 texture_ = 0; | |
| 231 } | |
| 232 } | |
| 233 | |
| OLD | NEW |