123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- // 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.
- #include "components/viz/test/gl_scaler_test_util.h"
- #include <algorithm>
- #include <cmath>
- #include <ostream>
- #include "base/check_op.h"
- #include "base/notreached.h"
- #include "third_party/skia/include/core/SkColor.h"
- #include "third_party/skia/include/core/SkImageInfo.h"
- #include "ui/gfx/geometry/rect.h"
- namespace viz {
- using ColorBar = GLScalerTestUtil::ColorBar;
- // static
- SkBitmap GLScalerTestUtil::AllocateRGBABitmap(const gfx::Size& size) {
- SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::Make(size.width(), size.height(),
- kRGBA_8888_SkColorType,
- kUnpremul_SkAlphaType));
- return bitmap;
- }
- // static
- uint8_t GLScalerTestUtil::ToClamped255(float value) {
- value = std::fma(value, 255.0f, 0.5f /* rounding */);
- return base::saturated_cast<uint8_t>(value);
- }
- // static
- std::vector<ColorBar> GLScalerTestUtil::GetScaledSMPTEColorBars(
- const gfx::Size& size) {
- std::vector<ColorBar> rects;
- const SkScalar scale_x =
- static_cast<SkScalar>(size.width()) / kSMPTEFullSize.width();
- const SkScalar scale_y =
- static_cast<SkScalar>(size.height()) / kSMPTEFullSize.height();
- for (const auto& cr : kSMPTEColorBars) {
- const SkRect rect =
- SkRect{cr.rect.fLeft * scale_x, cr.rect.fTop * scale_y,
- cr.rect.fRight * scale_x, cr.rect.fBottom * scale_y};
- rects.push_back(ColorBar{rect.round(), cr.color});
- }
- return rects;
- }
- // static
- SkBitmap GLScalerTestUtil::CreateSMPTETestImage(const gfx::Size& size) {
- SkBitmap result = AllocateRGBABitmap(size);
- // Set all pixels to a color that should not exist in the result. Later, a
- // sanity-check will ensure all pixels have been overwritten.
- constexpr SkColor4f kDeadColor = SkColor4f{0.678f, 0.745f, 0.937f, 0.871f};
- result.eraseColor(kDeadColor);
- // Set the pixels corresponding to each color bar.
- for (const auto& cr : GetScaledSMPTEColorBars(size)) {
- result.erase(cr.color, cr.rect);
- }
- // Validate that every pixel in the result bitmap has been touched by one of
- // the color bars.
- for (int y = 0; y < result.height(); ++y) {
- for (int x = 0; x < result.width(); ++x) {
- if (result.getColor4f(x, y) == kDeadColor) {
- NOTREACHED() << "TEST BUG: Error creating SMPTE test image. Bad size ("
- << size.ToString() << ")?";
- return result;
- }
- }
- }
- return result;
- }
- // static
- bool GLScalerTestUtil::LooksLikeSMPTETestImage(const SkBitmap& image,
- const gfx::Size& src_size,
- const gfx::Rect& src_rect,
- int fuzzy_pixels,
- float* max_color_diff) {
- if (image.width() <= 0 || image.height() <= 0) {
- return false;
- }
- const SkScalar offset_x = static_cast<SkScalar>(src_rect.x());
- const SkScalar offset_y = static_cast<SkScalar>(src_rect.y());
- const SkScalar scale_x =
- static_cast<SkScalar>(image.width()) / src_rect.width();
- const SkScalar scale_y =
- static_cast<SkScalar>(image.height()) / src_rect.height();
- float measured_max_diff = 0.0f;
- for (const auto& cr : GetScaledSMPTEColorBars(src_size)) {
- const SkIRect offset_rect = cr.rect.makeOffset(-offset_x, -offset_y);
- const SkIRect rect =
- SkRect{offset_rect.fLeft * scale_x, offset_rect.fTop * scale_y,
- offset_rect.fRight * scale_x, offset_rect.fBottom * scale_y}
- .round()
- .makeInset(fuzzy_pixels, fuzzy_pixels);
- for (int y = std::max(0, rect.fTop),
- y_end = std::min(image.height(), rect.fBottom);
- y < y_end; ++y) {
- for (int x = std::max(0, rect.fLeft),
- x_end = std::min(image.width(), rect.fRight);
- x < x_end; ++x) {
- const SkColor4f actual = image.getColor4f(x, y);
- measured_max_diff =
- std::max({measured_max_diff, std::abs((cr.color.fR) - (actual.fR)),
- std::abs((cr.color.fG) - (actual.fG)),
- std::abs((cr.color.fB) - (actual.fB)),
- std::abs((cr.color.fA) - (actual.fA))});
- }
- }
- }
- if (max_color_diff) {
- const int threshold = *max_color_diff;
- *max_color_diff = measured_max_diff;
- return measured_max_diff <= threshold;
- }
- return measured_max_diff == 0.0f;
- }
- // static
- SkBitmap GLScalerTestUtil::CreateCyclicalTestImage(
- const gfx::Size& size,
- CyclicalPattern pattern,
- const std::vector<SkColor4f>& cycle,
- size_t rotation) {
- CHECK(!cycle.empty());
- // Map SkColors to RGBA data. Also, applies the cycle |rotation| to simplify
- // the rest of the code below.
- std::vector<uint32_t> cycle_as_rgba(cycle.size());
- for (size_t i = 0; i < cycle.size(); ++i) {
- const SkColor4f color = cycle[(i + rotation) % cycle.size()];
- cycle_as_rgba[i] = ((static_cast<int>(color.fR * 255) << kRedShift) |
- (static_cast<int>(color.fG * 255) << kGreenShift) |
- (static_cast<int>(color.fB * 255) << kBlueShift) |
- (static_cast<int>(color.fA * 255) << kAlphaShift));
- }
- SkBitmap result = AllocateRGBABitmap(size);
- switch (pattern) {
- case HORIZONTAL_STRIPES:
- for (int y = 0; y < size.height(); ++y) {
- uint32_t* const pixels = result.getAddr32(0, y);
- const uint32_t stripe_rgba = cycle_as_rgba[y % cycle_as_rgba.size()];
- for (int x = 0; x < size.width(); ++x) {
- pixels[x] = stripe_rgba;
- }
- }
- break;
- case VERTICAL_STRIPES:
- for (int y = 0; y < size.height(); ++y) {
- uint32_t* const pixels = result.getAddr32(0, y);
- for (int x = 0; x < size.width(); ++x) {
- pixels[x] = cycle_as_rgba[x % cycle_as_rgba.size()];
- }
- }
- break;
- case STAGGERED:
- for (int y = 0; y < size.height(); ++y) {
- uint32_t* const pixels = result.getAddr32(0, y);
- for (int x = 0; x < size.width(); ++x) {
- pixels[x] = cycle_as_rgba[(x + y) % cycle_as_rgba.size()];
- }
- }
- break;
- }
- return result;
- }
- // static
- gfx::ColorSpace GLScalerTestUtil::DefaultRGBColorSpace() {
- return gfx::ColorSpace::CreateSRGB();
- }
- // static
- gfx::ColorSpace GLScalerTestUtil::DefaultYUVColorSpace() {
- return gfx::ColorSpace::CreateREC709();
- }
- // static
- void GLScalerTestUtil::ConvertRGBABitmapToYUV(SkBitmap* image) {
- CHECK_EQ(image->colorType(), kRGBA_8888_SkColorType);
- const auto transform = gfx::ColorTransform::NewColorTransform(
- DefaultRGBColorSpace(), DefaultYUVColorSpace());
- // Loop, transforming one row of pixels at a time.
- std::vector<gfx::ColorTransform::TriStim> stims(image->width());
- for (int y = 0; y < image->height(); ++y) {
- uint32_t* const pixels = image->getAddr32(0, y);
- for (int x = 0; x < image->width(); ++x) {
- stims[x].set_x(((pixels[x] >> kRedShift) & 0xff) / 255.0f);
- stims[x].set_y(((pixels[x] >> kGreenShift) & 0xff) / 255.0f);
- stims[x].set_z(((pixels[x] >> kBlueShift) & 0xff) / 255.0f);
- }
- transform->Transform(stims.data(), stims.size());
- for (int x = 0; x < image->width(); ++x) {
- pixels[x] = ((ToClamped255(stims[x].x()) << kRedShift) |
- (ToClamped255(stims[x].y()) << kGreenShift) |
- (ToClamped255(stims[x].z()) << kBlueShift) |
- (((pixels[x] >> kAlphaShift) & 0xff) << kAlphaShift));
- }
- }
- }
- // static
- SkBitmap GLScalerTestUtil::CopyAndConvertToRGBA(const SkBitmap& bitmap) {
- SkBitmap result;
- result.allocPixels(SkImageInfo::Make(
- bitmap.dimensions(), kRGBA_8888_SkColorType, kPremul_SkAlphaType));
- SkPixmap pixmap;
- bool success = bitmap.peekPixels(&pixmap) && result.writePixels(pixmap, 0, 0);
- CHECK(success);
- return result;
- }
- // static
- void GLScalerTestUtil::SwizzleBitmap(SkBitmap* image) {
- for (int y = 0; y < image->height(); ++y) {
- uint32_t* const pixels = image->getAddr32(0, y);
- for (int x = 0; x < image->width(); ++x) {
- pixels[x] = ((((pixels[x] >> kBlueShift) & 0xff) << kRedShift) |
- (((pixels[x] >> kGreenShift) & 0xff) << kGreenShift) |
- (((pixels[x] >> kRedShift) & 0xff) << kBlueShift) |
- (((pixels[x] >> kAlphaShift) & 0xff) << kAlphaShift));
- }
- }
- }
- // static
- SkBitmap GLScalerTestUtil::CreatePackedPlanarBitmap(const SkBitmap& source,
- int channel) {
- CHECK_EQ(source.width() % 4, 0);
- SkBitmap result =
- AllocateRGBABitmap(gfx::Size(source.width() / 4, source.height()));
- constexpr int kShiftForChannel[4] = {kRedShift, kGreenShift, kBlueShift,
- kAlphaShift};
- const int shift = kShiftForChannel[channel];
- for (int y = 0; y < result.height(); ++y) {
- const uint32_t* const src = source.getAddr32(0, y);
- uint32_t* const dst = result.getAddr32(0, y);
- for (int x = 0; x < result.width(); ++x) {
- // (src[0..3]) (dst)
- // RGBA RGBA RGBA RGBA --> RRRR (if channel is 0)
- dst[x] = ((((src[x * 4 + 0] >> shift) & 0xff) << kRedShift) |
- (((src[x * 4 + 1] >> shift) & 0xff) << kGreenShift) |
- (((src[x * 4 + 2] >> shift) & 0xff) << kBlueShift) |
- (((src[x * 4 + 3] >> shift) & 0xff) << kAlphaShift));
- }
- }
- return result;
- }
- // static
- void GLScalerTestUtil::UnpackPlanarBitmap(const SkBitmap& plane,
- int channel,
- SkBitmap* out) {
- // The heuristic below auto-adapts to subsampled plane sizes. However, there
- // are two cricital requirements: 1) |plane| cannot be empty; 2) |plane| must
- // have a size that cleanly unpacks to |out|'s size.
- CHECK_GT(plane.width(), 0);
- CHECK_GT(plane.height(), 0);
- const int col_sampling_ratio = out->width() / plane.width();
- CHECK_EQ(out->width() % plane.width(), 0)
- << " out->width()=" << out->width()
- << ", plane.width()=" << plane.width();
- CHECK_GT(col_sampling_ratio, 0);
- const int row_sampling_ratio = out->height() / plane.height();
- CHECK_EQ(out->height() % plane.height(), 0);
- CHECK_GT(row_sampling_ratio, 0);
- const int ch_sampling_ratio = col_sampling_ratio / 4;
- CHECK_GT(ch_sampling_ratio, 0);
- // These determine which single byte in each of |out|'s uint32_t-valued pixels
- // will be modified.
- constexpr int kShiftForChannel[4] = {kRedShift, kGreenShift, kBlueShift,
- kAlphaShift};
- const int output_shift = kShiftForChannel[channel];
- const uint32_t output_retain_mask = ~(UINT32_C(0xff) << output_shift);
- // Iterate over the pixels of |out|, sampling each of the 4 components of each
- // of |plane|'s pixels.
- for (int y = 0; y < out->height(); ++y) {
- const uint32_t* const src = plane.getAddr32(0, y / row_sampling_ratio);
- uint32_t* const dst = out->getAddr32(0, y);
- for (int x = 0; x < out->width(); ++x) {
- // Zero-out the existing byte (e.g., if channel==1, then "RGBA" → "R0BA").
- dst[x] &= output_retain_mask;
- // From |src|, grab one of "XYZW". Then, copy it to the target byte in
- // |dst| (e.g., if x_src_ch=3, then grab "W" from |src|, and |dst| changes
- // from "R0BA" to "RWBA").
- const int x_src = x / col_sampling_ratio;
- const int x_src_ch = (x / ch_sampling_ratio) % 4;
- dst[x] |= ((src[x_src] >> kShiftForChannel[x_src_ch]) & 0xff)
- << output_shift;
- }
- }
- }
- // static
- void GLScalerTestUtil::UnpackUVBitmap(const SkBitmap& plane, SkBitmap* out) {
- CHECK_GT(plane.width(), 0);
- CHECK_GT(plane.height(), 0);
- // The format of data in |plane| is as follows:
- //
- // UVUV UVUV UVUV
- // UVUV UVUV UVUV
- // UVUV UVUV UVUV
- //
- // One row of source of size |plane.width()| contains information about
- // 2 * |plane.width()| texels, and we want to sample them to populate
- // one row of |out->width()|, so we'll sample at the rate of
- //
- // col_sampling_ratio = out->width() / (2 * plane.width())
- //
- // This will allow us to find which "half-texel" in the source row to look at
- // for a corresponding texel in the output.
- const int col_sampling_ratio = out->width() / (2 * plane.width());
- CHECK_EQ(out->width() % (2 * plane.width()), 0);
- CHECK_GT(col_sampling_ratio, 0);
- const int row_sampling_ratio = out->height() / plane.height();
- CHECK_EQ(out->height() % plane.height(), 0);
- CHECK_GT(row_sampling_ratio, 0);
- // These determine which single byte in each of |out|'s uint32_t-valued pixels
- // will be modified.
- constexpr int kShiftForChannel[4] = {kRedShift, kGreenShift, kBlueShift,
- kAlphaShift};
- constexpr uint32_t zero_green_mask = ~(UINT32_C(0xff) << kGreenShift);
- constexpr uint32_t zero_blue_mask = ~(UINT32_C(0xff) << kBlueShift);
- constexpr uint32_t zero_green_blue_mask = zero_green_mask & zero_blue_mask;
- // Iterate over all the pixels of |out|, calculate where the data for that
- // said pixel is.
- for (int y = 0; y < out->height(); ++y) {
- const uint32_t* const src = plane.getAddr32(0, y / row_sampling_ratio);
- uint32_t* const dst = out->getAddr32(0, y);
- for (int x = 0; x < out->width(); ++x) {
- // Zero-out the existing byte (e.g., "RGBA" → "R00A").
- dst[x] &= zero_green_blue_mask;
- // Find which half-texel to look at:
- const int src_half_texel = x / col_sampling_ratio;
- // The |src_half_texel| belongs to a texel:
- const int src_texel = src_half_texel / 2;
- // The |src_half_texel| spans 2 channels and starts at channel:
- const int src_channel = 2 * (src_half_texel % 2);
- // Grab the 2 consecutive channels, starting at |src_channel|:
- dst[x] |= ((src[src_texel] >> kShiftForChannel[src_channel]) & 0xff)
- << kGreenShift;
- dst[x] |= ((src[src_texel] >> kShiftForChannel[src_channel + 1]) & 0xff)
- << kBlueShift;
- }
- }
- }
- // static
- SkBitmap GLScalerTestUtil::CreateVerticallyFlippedBitmap(
- const SkBitmap& source) {
- SkBitmap bitmap;
- bitmap.allocPixels(source.info());
- CHECK_EQ(bitmap.rowBytes(), source.rowBytes());
- for (int y = 0; y < bitmap.height(); ++y) {
- const int src_y = bitmap.height() - y - 1;
- memcpy(bitmap.getAddr32(0, y), source.getAddr32(0, src_y),
- bitmap.rowBytes());
- }
- return bitmap;
- }
- // The area and color of the bars in a 1920x1080 HD SMPTE color bars test image
- // (https://commons.wikimedia.org/wiki/File:SMPTE_Color_Bars_16x9.svg). The gray
- // linear gradient bar is defined as half solid 0-level black and half solid
- // full-intensity white).
- const ColorBar GLScalerTestUtil::kSMPTEColorBars[30] = {
- {{0, 240, 630}, SkColor4f{0.4f, 0.4f, 0.4f, 1.0f}},
- {{240, 0, 445, 630}, SkColor4f{0.749f, 0.749f, 0.749f, 1.0f}},
- {{0, 651, 445, 630}, SkColor4f{0.749f, 0.749f, 0.0f, 1.0f}},
- {{0, 857, 651, 630}, SkColor4f{0.0f, 0.749f, 0.749f, 1.0f}},
- {{0, 857, 630, 1063}, SkColor4f{0.0f, 0.749f, 0.0f, 1.0f}},
- {{0, 1269, 630, 1063}, SkColor4f{0.749f, 0.0f, 0.749f, 1.0f}},
- {{0, 1475, 1269, 630}, SkColor4f{0.749f, 0.0f, 0.0f, 1.0f}},
- {{0, 1475, 1680, 630}, SkColor4f{0.0f, 0.0f, 0.749f, 1.0f}},
- {{1680, 0, 1920, 630}, SkColor4f{0.4f, 0.4f, 0.4f, 1.0f}},
- {{0, 240, 630, 720}, SkColor4f{0.0f, 1.0f, 1.0f, 1.0f}},
- {{240, 445, 630, 720}, SkColor4f{0.0f, 0.129f, 0.298f, 1.0f}},
- {{1680, 445, 630, 720}, SkColor4f{0.749f, 0.749f, 0.749f, 1.0f}},
- {{1680, 1920, 630, 720}, SkColor4f{0.0f, 0.0f, 1.0f, 1.0f}},
- {{0, 240, 810, 720}, SkColor4f{1.0f, 1.0f, 0.0f, 1.0f}},
- {{240, 810, 445, 720}, SkColor4f{0.196f, 0.0f, 0.416f, 1.0f}},
- {{720, 810, 445, 1063}, SkColor4f{0.0f, 0.0f, 0.0f, 1.0f}},
- {{720, 810, 1680, 1063}, SkColor4f{1.0f, 1.0f, 1.0f, 1.0f}},
- {{1680, 810, 1920, 720}, SkColor4f{1.0f, 0.0f, 0.0f, 1.0f}},
- {{0, 240, 810, 1080}, SkColor4f{0.149f, 0.149f, 0.149f, 1.0f}},
- {{240, 810, 1080, 549}, SkColor4f{0.0f, 0.0f, 0.0f, 1.0f}},
- {{960, 810, 1080, 549}, SkColor4f{1.0f, 1.0f, 1.0f, 1.0f}},
- {{960, 810, 1131, 1080}, SkColor4f{0.0f, 0.0f, 0.0f, 1.0f}},
- {{1200, 810, 1131, 1080}, SkColor4f{0.0f, 0.0f, 0.0f, 1.0f}},
- {{1200, 810, 1268, 1080}, SkColor4f{0.0f, 0.0f, 0.0f, 1.0f}},
- {{1080, 1337, 810, 1268}, SkColor4f{0.02f, 0.02f, 0.02f, 1.0f}},
- {{1080, 1337, 810, 1405}, SkColor4f{0.0f, 0.0f, 0.0f, 1.0f}},
- {{1080, 1474, 810, 1405}, SkColor4f{0.039f, 0.039f, 0.039f, 1.0f}},
- {{1680, 1474, 810, 1080}, SkColor4f{0.0f, 0.0f, 0.0f, 1.0f}},
- {{1680, 810, 1080, 1920}, SkColor4f{0.149f, 0.149f, 0.149f, 1.0f}},
- };
- constexpr gfx::Size GLScalerTestUtil::kSMPTEFullSize;
- GLScalerTestTextureHelper::GLScalerTestTextureHelper(
- gpu::gles2::GLES2Interface* gl)
- : gl_(gl) {
- CHECK(gl_);
- }
- GLScalerTestTextureHelper::~GLScalerTestTextureHelper() {
- gl_->DeleteTextures(textures_to_delete_.size(), textures_to_delete_.data());
- textures_to_delete_.clear();
- }
- GLuint GLScalerTestTextureHelper::CreateTexture(const gfx::Size& size) {
- GLuint texture = 0;
- gl_->GenTextures(1, &texture);
- gl_->BindTexture(GL_TEXTURE_2D, texture);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
- GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- gl_->BindTexture(GL_TEXTURE_2D, 0);
- if (texture) {
- textures_to_delete_.push_back(texture);
- }
- return texture;
- }
- GLuint GLScalerTestTextureHelper::UploadTexture(const SkBitmap& bitmap) {
- CHECK_EQ(bitmap.colorType(), kRGBA_8888_SkColorType);
- GLuint texture = 0;
- gl_->GenTextures(1, &texture);
- gl_->BindTexture(GL_TEXTURE_2D, texture);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap.width(), bitmap.height(), 0,
- GL_RGBA, GL_UNSIGNED_BYTE, bitmap.getAddr32(0, 0));
- gl_->BindTexture(GL_TEXTURE_2D, 0);
- if (texture) {
- textures_to_delete_.push_back(texture);
- }
- return texture;
- }
- SkBitmap GLScalerTestTextureHelper::DownloadTexture(GLuint texture,
- const gfx::Size& size) {
- GLuint framebuffer = 0;
- gl_->GenFramebuffers(1, &framebuffer);
- gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- texture, 0);
- SkBitmap result = GLScalerTestUtil::AllocateRGBABitmap(size);
- gl_->ReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE,
- result.getAddr32(0, 0));
- gl_->DeleteFramebuffers(1, &framebuffer);
- return result;
- }
- } // namespace viz
|