| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COMPONENTS_VIZ_COMMON_GL_SCALER_H_ |
| #define COMPONENTS_VIZ_COMMON_GL_SCALER_H_ |
| |
| #include <stdint.h> |
| |
| #include "base/compiler_specific.h" |
| #include "base/macros.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "components/viz/common/gpu/context_lost_observer.h" |
| #include "components/viz/common/viz_common_export.h" |
| #include "gpu/command_buffer/client/gles2_interface.h" |
| #include "ui/gfx/color_space.h" |
| #include "ui/gfx/geometry/vector2d.h" |
| |
| namespace gfx { |
| class Vector2dF; |
| class Rect; |
| class Size; |
| } // namespace gfx |
| |
| namespace viz { |
| |
| class ContextProvider; |
| |
| // A high-performance texture scaler for use with an OpenGL ES 2.0 context. It |
| // can be configured to operate at different quality levels, manages/converts |
| // color spaces, and optionally re-arranges/formats data in output textures for |
| // use with more-efficient texture readback pipelines. |
| class VIZ_COMMON_EXPORT GLScaler : public ContextLostObserver { |
| public: |
| struct VIZ_COMMON_EXPORT Parameters { |
| // Relative scale from/to factors. Both of these must be non-zero. |
| gfx::Vector2d scale_from = gfx::Vector2d(1, 1); |
| gfx::Vector2d scale_to = gfx::Vector2d(1, 1); |
| |
| // The color space of the source texture and the desired color space of the |
| // output texture. If |source_color_space| is not set (or invalid), sRGB is |
| // assumed. If |output_color_space| is not set (or invalid), the source |
| // color space is assumed. |
| gfx::ColorSpace source_color_space; |
| gfx::ColorSpace output_color_space; |
| |
| // Enable color management heuristics, using higher precision texture and |
| // gamma-aware scaling? |
| // |
| // When disabled, the gamma of the source color space and other concerns are |
| // ignored and 8-bit precision is used. |
| // |
| // When enabled, scaling occurs in a linear color space with 16-bit floats. |
| // This produces excellent results for virtually all color spaces while |
| // typically requiring twice the memory and execution resources. The caller |
| // must ensure the GL context supports the use of GL_RGBA16F format |
| // textures. |
| // |
| // Relevant reading: http://www.ericbrasseur.org/gamma.html |
| bool enable_precise_color_management = false; |
| |
| // Selects the trade-off between quality and speed. |
| enum class Quality : int8_t { |
| // Bilinear single pass. Fastest possible. Do not use this unless the GL |
| // implementation is so slow that the other quality options won't work. |
| FAST, |
| |
| // Bilinear upscale + N * 50% bilinear downscales. This is still fast |
| // enough for general-purpose use, and image quality is nearly as good as |
| // BEST when downscaling. |
| GOOD, |
| |
| // Bicubic upscale + N * 50% bicubic downscales. Produces very good |
| // quality scaled images, but it's 2-8x slower than the "GOOD" quality. |
| BEST, |
| } quality = Quality::GOOD; |
| |
| // Is the source texture Y-flipped (i.e., the origin is the lower-left |
| // corner and not the upper-left corner)? Most GL textures are Y-flipped. |
| // This information is required so that the scaler can correctly compute the |
| // sampling region. |
| bool is_flipped_source = true; |
| |
| // Should the output be vertically flipped? Usually, this is used when the |
| // source is not Y-flipped, but the destination texture needs to be. Or, it |
| // can be used to draw the final output upside-down to avoid having to copy |
| // the rows in reverse order after a glReadPixels(). |
| bool flip_output = false; |
| |
| // Optionally rearrange the image data for export. Generally, this is used |
| // to make later readback steps more efficient (e.g., using glReadPixels() |
| // will produce the raw bytes in their correct locations). |
| // |
| // Output textures are assumed to be using one of the 4-channel RGBA |
| // formats. While it may be more "proper" to use a single-component texture |
| // format for the planar-oriented image data, not all GL implementations |
| // support the use of those formats. However, all must support at least |
| // GL_RGBA. Therefore, each RGBA pixel is treated as a generic "vec4" (a |
| // quad of values). |
| // |
| // When using this feature, it is usually necessary to adjust the |
| // |output_rect| passed to Scale() or ScaleToMultipleOutputs(). See notes |
| // below. |
| enum class ExportFormat : int8_t { |
| // Do not rearrange the image data: |
| // |
| // (interleaved quads) (interleaved quads) |
| // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA |
| // RGBA RGBA RGBA RGBA --> RGBA RGBA RGBA RGBA |
| // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA |
| INTERLEAVED_QUADS, |
| |
| // Select one color channel, packing each of 4 pixels' values into the 4 |
| // elements of one output quad. |
| // |
| // For example, for CHANNEL_0: |
| // |
| // (interleaved quads) (channel 0) |
| // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA RRRR RRRR |
| // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA --> RRRR RRRR |
| // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA RRRR RRRR |
| // |
| // Note: Because of this packing, the horizontal coordinates of the |
| // |output_rect| used with Scale() should be divided by 4. |
| CHANNEL_0, |
| CHANNEL_1, |
| CHANNEL_2, |
| CHANNEL_3, |
| |
| // I422 sampling, delivered via two output textures (NV61 format): The |
| // first texture is produced the same as CHANNEL_0, while the second |
| // texture contains CHANNEL_1 and CHANNEL_2 at half-width interleaved and |
| // full-height. For example, if this is combined with RGB→YUV color space |
| // conversion: |
| // |
| // (interleaved quads) |
| // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA |
| // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA |
| // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA |
| // | |
| // | (luma plane) (chroma, interleaved) |
| // | YYYY YYYY UVUV UVUV |
| // +---> { YYYY YYYY + UVUV UVUV } |
| // YYYY YYYY UVUV UVUV |
| // |
| // Note: Because of this packing, the horizontal coordinates of the |
| // |output_rect| used with ScaleToMultipleOutputs() should be divided by |
| // 4. |
| // Note 2: This requires a GL context that supports multiple render |
| // targets with at least two draw buffers. |
| NV61, |
| |
| // Deinterleave into two output textures. |
| // |
| // UVUV UVUV UUUU VVVV |
| // UVUV UVUV --> { UUUU + VVVV } |
| // UVUV UVUV UUUU VVVV |
| // |
| // Note: Because of this packing, the horizontal coordinates of the |
| // |output_rect| used with ScaleToMultipleOutputs() should be divided by |
| // 2. |
| // Note 2: This requires a GL context that supports multiple render |
| // targets with at least two draw buffers. |
| DEINTERLEAVE_PAIRWISE, |
| } export_format = ExportFormat::INTERLEAVED_QUADS; |
| |
| // Optionally swizzle the ordering of the values in each output quad. If the |
| // output of the scaler is not going to be read back (e.g., used with |
| // glReadPixels()), simply leave these unchanged. Otherwise, changing this |
| // allows a read-back pipeline to use the native format of the platform to |
| // avoid having to perform extra "BGRA⇄RGBA swizzle" memcpy's. Usually, this |
| // should match the format to be used with glReadPixels(), and that should |
| // match the GL_IMPLEMENTATION_COLOR_READ_FORMAT. |
| GLenum swizzle[2] = { |
| GL_RGBA, // For |dest_texture_0|. |
| GL_RGBA, // For |dest_texture_1|. |
| }; |
| |
| Parameters(); |
| ~Parameters(); |
| }; |
| |
| explicit GLScaler(scoped_refptr<ContextProvider> context_provider); |
| |
| ~GLScaler() final; |
| |
| // Returns true if the GL context provides the necessary support for enabling |
| // precise color management (see Parameters::enable_precise_color_management). |
| bool SupportsPreciseColorManagement() const; |
| |
| // Returns the maximum number of simultaneous drawing buffers supported by the |
| // GL context. Certain Parameters can only be used when this is more than 1. |
| int GetMaxDrawBuffersSupported() const; |
| |
| // [Re]Configure the scaler with the given |new_params|. Returns true on |
| // success, or false on failure. |
| bool Configure(const Parameters& new_params) WARN_UNUSED_RESULT; |
| |
| // Returns the currently-configured and resolved Parameters. Note that these |
| // Parameters might not be exactly the same as those that were passed to |
| // Configure() because some properties (e.g., color spaces) are auto-resolved. |
| // Results are undefined if Configure() has never been called successfully. |
| const Parameters& params() const { return params_; } |
| |
| // Scales a portion of |src_texture| and draws the result into |dest_texture| |
| // at offset (0, 0). Returns true to indicate success, or false if this |
| // GLScaler is not valid. |
| // |
| // |src_texture_size| is the full, allocated size of the |src_texture|. This |
| // is required for computing texture coordinate transforms (and only because |
| // the OpenGL ES 2.0 API lacks the ability to query this info). |
| // |
| // |src_offset| is the offset in the source texture corresponding to point |
| // (0,0) in the source/output coordinate spaces. This prevents the need for |
| // extra texture copies just to re-position the source coordinate system. |
| // |
| // |output_rect| selects the region to draw (in the scaled, not the source, |
| // coordinate space). This is used to save work in cases where only a portion |
| // needs to be re-scaled. The implementation will back-compute, internally, to |
| // determine the region of the |src_texture| to sample. |
| // |
| // WARNING: The output will always be placed at (0, 0) in the |dest_texture|, |
| // and not at |output_rect.origin()|. |
| // |
| // Note that the |src_texture| will have the min/mag filter set to GL_LINEAR |
| // and wrap_s/t set to CLAMP_TO_EDGE in this call. |
| bool Scale(GLuint src_texture, |
| const gfx::Size& src_texture_size, |
| const gfx::Vector2dF& src_offset, |
| GLuint dest_texture, |
| const gfx::Rect& output_rect) WARN_UNUSED_RESULT { |
| return ScaleToMultipleOutputs(src_texture, src_texture_size, src_offset, |
| dest_texture, 0, output_rect); |
| } |
| |
| // Same as above, but for use cases where there are two output textures drawn |
| // (see Parameters::ExportFormat). |
| bool ScaleToMultipleOutputs(GLuint src_texture, |
| const gfx::Size& src_texture_size, |
| const gfx::Vector2dF& src_offset, |
| GLuint dest_texture_0, |
| GLuint dest_texture_1, |
| const gfx::Rect& output_rect) WARN_UNUSED_RESULT; |
| |
| // Given the |src_texture_size|, |src_offset| and |output_rect| arguments that |
| // would be passed to Scale(), compute the region of pixels in the source |
| // texture that would be sampled to produce a scaled result. The result is |
| // stored in |sampling_rect|, along with the |offset| to the (0,0) point |
| // relative to |sampling_rect|'s origin. Returns true to indicate success, or |
| // false if this GLScaler is not valid. |
| // |
| // This is used by clients that need to know the minimal portion of a source |
| // buffer that must be copied without affecting Scale()'s results. This |
| // method also accounts for vertical flipping. |
| bool ComputeRegionOfInfluence(const gfx::Size& src_texture_size, |
| const gfx::Vector2dF& src_offset, |
| const gfx::Rect& output_rect, |
| gfx::Rect* sampling_rect, |
| gfx::Vector2dF* offset) const |
| WARN_UNUSED_RESULT; |
| |
| // Returns true if from:to represent the same scale ratio as that specified in |
| // |params|. |
| static bool ParametersHasSameScaleRatio(const Parameters& params, |
| const gfx::Vector2d& from, |
| const gfx::Vector2d& to); |
| |
| private: |
| using GLES2Interface = gpu::gles2::GLES2Interface; |
| |
| // ContextLostObserver implementation. |
| void OnContextLost() final; |
| |
| // The provider of the GL context. This is non-null while the GL context is |
| // valid and GLScaler is observing for context loss. |
| scoped_refptr<ContextProvider> context_provider_; |
| |
| // Set by Configure() to the resolved set of Parameters. |
| Parameters params_; |
| |
| // The maximum number of simultaneous draw buffers, lazy initialized by |
| // GetMaxDrawBuffersSupported(). -1 means "not yet known." |
| mutable int max_draw_buffers_ = -1; |
| |
| DISALLOW_COPY_AND_ASSIGN(GLScaler); |
| }; |
| |
| } // namespace viz |
| |
| #endif // COMPONENTS_VIZ_COMMON_GL_SCALER_H_ |