1 // Copyright (c) 2012 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 #ifndef CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_ 6 #define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_ 7 8 #include "base/atomicops.h" 9 #include "base/basictypes.h" 10 #include "base/callback.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "content/common/content_export.h" 13 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 14 15 namespace gfx { 16 class Rect; 17 class Size; 18 } 19 20 namespace gpu { 21 class ContextSupport; 22 struct Mailbox; 23 } 24 25 namespace media { 26 class VideoFrame; 27 }; 28 29 class SkRegion; 30 31 namespace content { 32 33 class GLHelperScaling; 34 35 class ScopedWebGLId { 36 public: 37 typedef void (blink::WebGraphicsContext3D::*DeleteFunc)(WebGLId); 38 ScopedWebGLId(blink::WebGraphicsContext3D* context, 39 WebGLId id, 40 DeleteFunc delete_func) 41 : context_(context), 42 id_(id), 43 delete_func_(delete_func) { 44 } 45 46 operator WebGLId() const { 47 return id_; 48 } 49 50 WebGLId id() const { return id_; } 51 52 WebGLId Detach() { 53 WebGLId id = id_; 54 id_ = 0; 55 return id; 56 } 57 58 ~ScopedWebGLId() { 59 if (id_ != 0) { 60 (context_->*delete_func_)(id_); 61 } 62 } 63 64 private: 65 blink::WebGraphicsContext3D* context_; 66 WebGLId id_; 67 DeleteFunc delete_func_; 68 69 DISALLOW_COPY_AND_ASSIGN(ScopedWebGLId); 70 }; 71 72 class ScopedBuffer : public ScopedWebGLId { 73 public: 74 ScopedBuffer(blink::WebGraphicsContext3D* context, 75 WebGLId id) 76 : ScopedWebGLId(context, 77 id, 78 &blink::WebGraphicsContext3D::deleteBuffer) {} 79 }; 80 81 class ScopedFramebuffer : public ScopedWebGLId { 82 public: 83 ScopedFramebuffer(blink::WebGraphicsContext3D* context, 84 WebGLId id) 85 : ScopedWebGLId(context, 86 id, 87 &blink::WebGraphicsContext3D::deleteFramebuffer) {} 88 }; 89 90 class ScopedProgram : public ScopedWebGLId { 91 public: 92 ScopedProgram(blink::WebGraphicsContext3D* context, 93 WebGLId id) 94 : ScopedWebGLId(context, 95 id, 96 &blink::WebGraphicsContext3D::deleteProgram) {} 97 }; 98 99 class ScopedShader : public ScopedWebGLId { 100 public: 101 ScopedShader(blink::WebGraphicsContext3D* context, 102 WebGLId id) 103 : ScopedWebGLId(context, 104 id, 105 &blink::WebGraphicsContext3D::deleteShader) {} 106 }; 107 108 class ScopedTexture : public ScopedWebGLId { 109 public: 110 ScopedTexture(blink::WebGraphicsContext3D* context, 111 WebGLId id) 112 : ScopedWebGLId(context, 113 id, 114 &blink::WebGraphicsContext3D::deleteTexture) {} 115 }; 116 117 template <blink::WGC3Denum target> 118 class ScopedBinder { 119 public: 120 typedef void (blink::WebGraphicsContext3D::*BindFunc)(blink::WGC3Denum, 121 WebGLId); 122 ScopedBinder(blink::WebGraphicsContext3D* context, 123 WebGLId id, 124 BindFunc bind_func) 125 : context_(context), 126 bind_func_(bind_func) { 127 (context_->*bind_func_)(target, id); 128 } 129 130 virtual ~ScopedBinder() { 131 (context_->*bind_func_)(target, 0); 132 } 133 134 private: 135 blink::WebGraphicsContext3D* context_; 136 BindFunc bind_func_; 137 138 DISALLOW_COPY_AND_ASSIGN(ScopedBinder); 139 }; 140 141 template <blink::WGC3Denum target> 142 class ScopedBufferBinder : ScopedBinder<target> { 143 public: 144 ScopedBufferBinder(blink::WebGraphicsContext3D* context, 145 WebGLId id) 146 : ScopedBinder<target>( 147 context, 148 id, 149 &blink::WebGraphicsContext3D::bindBuffer) {} 150 }; 151 152 template <blink::WGC3Denum target> 153 class ScopedFramebufferBinder : ScopedBinder<target> { 154 public: 155 ScopedFramebufferBinder(blink::WebGraphicsContext3D* context, 156 WebGLId id) 157 : ScopedBinder<target>( 158 context, 159 id, 160 &blink::WebGraphicsContext3D::bindFramebuffer) {} 161 }; 162 163 template <blink::WGC3Denum target> 164 class ScopedTextureBinder : ScopedBinder<target> { 165 public: 166 ScopedTextureBinder(blink::WebGraphicsContext3D* context, 167 WebGLId id) 168 : ScopedBinder<target>( 169 context, 170 id, 171 &blink::WebGraphicsContext3D::bindTexture) {} 172 }; 173 174 class ScopedFlush { 175 public: 176 explicit ScopedFlush(blink::WebGraphicsContext3D* context) 177 : context_(context) { 178 } 179 180 ~ScopedFlush() { 181 context_->flush(); 182 } 183 184 private: 185 blink::WebGraphicsContext3D* context_; 186 187 DISALLOW_COPY_AND_ASSIGN(ScopedFlush); 188 }; 189 190 191 class ReadbackYUVInterface; 192 193 // Provides higher level operations on top of the blink::WebGraphicsContext3D 194 // interfaces. 195 class CONTENT_EXPORT GLHelper { 196 public: 197 GLHelper(blink::WebGraphicsContext3D* context, 198 gpu::ContextSupport* context_support); 199 ~GLHelper(); 200 201 enum ScalerQuality { 202 // Bilinear single pass, fastest possible. 203 SCALER_QUALITY_FAST = 1, 204 205 // Bilinear upscale + N * 50% bilinear downscales. 206 // This is still fast enough for most purposes and 207 // Image quality is nearly as good as the BEST option. 208 SCALER_QUALITY_GOOD = 2, 209 210 // Bicubic upscale + N * 50% bicubic downscales. 211 // Produces very good quality scaled images, but it's 212 // 2-8x slower than the "GOOD" quality, so it's not always 213 // worth it. 214 SCALER_QUALITY_BEST = 3, 215 }; 216 217 218 // Copies the block of pixels specified with |src_subrect| from |src_texture|, 219 // scales it to |dst_size|, and writes it into |out|. 220 // |src_size| is the size of |src_texture|. The result is of format GL_BGRA 221 // and is potentially flipped vertically to make it a correct image 222 // representation. |callback| is invoked with the copy result when the copy 223 // operation has completed. 224 // Note that the src_texture will have the min/mag filter set to GL_LINEAR 225 // and wrap_s/t set to CLAMP_TO_EDGE in this call. 226 void CropScaleReadbackAndCleanTexture( 227 blink::WebGLId src_texture, 228 const gfx::Size& src_size, 229 const gfx::Rect& src_subrect, 230 const gfx::Size& dst_size, 231 unsigned char* out, 232 const base::Callback<void(bool)>& callback); 233 234 // Copies the block of pixels specified with |src_subrect| from |src_mailbox|, 235 // scales it to |dst_size|, and writes it into |out|. 236 // |src_size| is the size of |src_mailbox|. The result is of format GL_BGRA 237 // and is potentially flipped vertically to make it a correct image 238 // representation. |callback| is invoked with the copy result when the copy 239 // operation has completed. 240 // Note that the texture bound to src_mailbox will have the min/mag filter set 241 // to GL_LINEAR and wrap_s/t set to CLAMP_TO_EDGE in this call. src_mailbox is 242 // assumed to be GL_TEXTURE_2D. 243 void CropScaleReadbackAndCleanMailbox( 244 const gpu::Mailbox& src_mailbox, 245 uint32 sync_point, 246 const gfx::Size& src_size, 247 const gfx::Rect& src_subrect, 248 const gfx::Size& dst_size, 249 unsigned char* out, 250 const base::Callback<void(bool)>& callback); 251 252 // Copies the texture data out of |texture| into |out|. |size| is the 253 // size of the texture. No post processing is applied to the pixels. The 254 // texture is assumed to have a format of GL_RGBA with a pixel type of 255 // GL_UNSIGNED_BYTE. This is a blocking call that calls glReadPixels on this 256 // current context. 257 void ReadbackTextureSync(blink::WebGLId texture, 258 const gfx::Rect& src_rect, 259 unsigned char* out); 260 261 // Creates a copy of the specified texture. |size| is the size of the texture. 262 // Note that the src_texture will have the min/mag filter set to GL_LINEAR 263 // and wrap_s/t set to CLAMP_TO_EDGE in this call. 264 blink::WebGLId CopyTexture(blink::WebGLId texture, 265 const gfx::Size& size); 266 267 // Creates a scaled copy of the specified texture. |src_size| is the size of 268 // the texture and |dst_size| is the size of the resulting copy. 269 // Note that the src_texture will have the min/mag filter set to GL_LINEAR 270 // and wrap_s/t set to CLAMP_TO_EDGE in this call. 271 blink::WebGLId CopyAndScaleTexture( 272 blink::WebGLId texture, 273 const gfx::Size& src_size, 274 const gfx::Size& dst_size, 275 bool vertically_flip_texture, 276 ScalerQuality quality); 277 278 // Returns the shader compiled from the source. 279 blink::WebGLId CompileShaderFromSource(const blink::WGC3Dchar* source, 280 blink::WGC3Denum type); 281 282 // Copies all pixels from |previous_texture| into |texture| that are 283 // inside the region covered by |old_damage| but not part of |new_damage|. 284 void CopySubBufferDamage(blink::WebGLId texture, 285 blink::WebGLId previous_texture, 286 const SkRegion& new_damage, 287 const SkRegion& old_damage); 288 289 // Simply creates a texture. 290 blink::WebGLId CreateTexture(); 291 // Deletes a texture. 292 void DeleteTexture(blink::WebGLId texture_id); 293 294 // Insert a sync point into the GL command buffer. 295 uint32 InsertSyncPoint(); 296 // Wait for the sync point before executing further GL commands. 297 void WaitSyncPoint(uint32 sync_point); 298 299 // Creates a mailbox that is attached to the given texture id, and a sync 300 // point to wait on before using the mailbox. Returns an empty mailbox on 301 // failure. 302 // Note the texture is assumed to be GL_TEXTURE_2D. 303 gpu::Mailbox ProduceMailboxFromTexture(blink::WebGLId texture_id, 304 uint32* sync_point); 305 306 // Creates a texture and consumes a mailbox into it. Returns 0 on failure. 307 // Note the mailbox is assumed to be GL_TEXTURE_2D. 308 blink::WebGLId ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, 309 uint32 sync_point); 310 311 // Resizes the texture's size to |size|. 312 void ResizeTexture(blink::WebGLId texture, const gfx::Size& size); 313 314 // Copies the framebuffer data given in |rect| to |texture|. 315 void CopyTextureSubImage(blink::WebGLId texture, const gfx::Rect& rect); 316 317 // Copies the all framebuffer data to |texture|. |size| specifies the 318 // size of the framebuffer. 319 void CopyTextureFullImage(blink::WebGLId texture, const gfx::Size& size); 320 321 // A scaler will cache all intermediate textures and programs 322 // needed to scale from a specified size to a destination size. 323 // If the source or destination sizes changes, you must create 324 // a new scaler. 325 class CONTENT_EXPORT ScalerInterface { 326 public: 327 ScalerInterface() {} 328 virtual ~ScalerInterface() {} 329 330 // Note that the src_texture will have the min/mag filter set to GL_LINEAR 331 // and wrap_s/t set to CLAMP_TO_EDGE in this call. 332 virtual void Scale(blink::WebGLId source_texture, 333 blink::WebGLId dest_texture) = 0; 334 virtual const gfx::Size& SrcSize() = 0; 335 virtual const gfx::Rect& SrcSubrect() = 0; 336 virtual const gfx::Size& DstSize() = 0; 337 }; 338 339 // Note that the quality may be adjusted down if texture 340 // allocations fail or hardware doesn't support the requtested 341 // quality. Note that ScalerQuality enum is arranged in 342 // numerical order for simplicity. 343 ScalerInterface* CreateScaler(ScalerQuality quality, 344 const gfx::Size& src_size, 345 const gfx::Rect& src_subrect, 346 const gfx::Size& dst_size, 347 bool vertically_flip_texture, 348 bool swizzle); 349 350 // Create a readback pipeline that will scale a subsection of the source 351 // texture, then convert it to YUV422 planar form and then read back that. 352 // This reduces the amount of memory read from GPU to CPU memory by a factor 353 // 2.6, which can be quite handy since readbacks have very limited speed 354 // on some platforms. All values in |dst_size| and |dst_subrect| must be 355 // a multiple of two. If |use_mrt| is true, the pipeline will try to optimize 356 // the YUV conversion using the multi-render-target extension. |use_mrt| 357 // should only be set to false for testing. 358 ReadbackYUVInterface* CreateReadbackPipelineYUV( 359 ScalerQuality quality, 360 const gfx::Size& src_size, 361 const gfx::Rect& src_subrect, 362 const gfx::Size& dst_size, 363 const gfx::Rect& dst_subrect, 364 bool flip_vertically, 365 bool use_mrt); 366 367 // Returns the maximum number of draw buffers available, 368 // 0 if GL_EXT_draw_buffers is not available. 369 blink::WGC3Dint MaxDrawBuffers(); 370 371 protected: 372 class CopyTextureToImpl; 373 374 // Creates |copy_texture_to_impl_| if NULL. 375 void InitCopyTextToImpl(); 376 // Creates |scaler_impl_| if NULL. 377 void InitScalerImpl(); 378 379 blink::WebGraphicsContext3D* context_; 380 gpu::ContextSupport* context_support_; 381 scoped_ptr<CopyTextureToImpl> copy_texture_to_impl_; 382 scoped_ptr<GLHelperScaling> scaler_impl_; 383 384 DISALLOW_COPY_AND_ASSIGN(GLHelper); 385 }; 386 387 // Similar to a ScalerInterface, a yuv readback pipeline will 388 // cache a scaler and all intermediate textures and frame buffers 389 // needed to scale, crop, letterbox and read back a texture from 390 // the GPU into CPU-accessible RAM. A single readback pipeline 391 // can handle multiple outstanding readbacks at the same time, but 392 // if the source or destination sizes change, you'll need to create 393 // a new readback pipeline. 394 class CONTENT_EXPORT ReadbackYUVInterface { 395 public: 396 ReadbackYUVInterface() {} 397 virtual ~ReadbackYUVInterface() {} 398 399 // Note that |target| must use YV12 format. 400 virtual void ReadbackYUV( 401 const gpu::Mailbox& mailbox, 402 uint32 sync_point, 403 const scoped_refptr<media::VideoFrame>& target, 404 const base::Callback<void(bool)>& callback) = 0; 405 virtual GLHelper::ScalerInterface* scaler() = 0; 406 }; 407 408 } // namespace content 409 410 #endif // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_ 411