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