Index: ui/gl/gl_image_unittest.cc |
diff --git a/ui/gl/gl_image_unittest.cc b/ui/gl/gl_image_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8cc952ac1aff41c0bbf82e0c3926d06d2f1620d5 |
--- /dev/null |
+++ b/ui/gl/gl_image_unittest.cc |
@@ -0,0 +1,532 @@ |
+// Copyright 2015 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 "ui/gl/gl_image.h" |
+ |
+#include <vector> |
+ |
+#include "base/memory/ref_counted_memory.h" |
+#include "base/memory/shared_memory.h" |
+#include "base/strings/stringprintf.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "third_party/skia/include/core/SkCanvas.h" |
+#include "third_party/skia/include/core/SkColor.h" |
+#include "third_party/skia/include/core/SkSurface.h" |
+#include "ui/gfx/buffer_format_util.h" |
+#include "ui/gfx/buffer_types.h" |
+#include "ui/gl/gl_bindings.h" |
+#include "ui/gl/gl_context.h" |
+#include "ui/gl/gl_image_ref_counted_memory.h" |
+#include "ui/gl/gl_image_shared_memory.h" |
+#include "ui/gl/gl_implementation.h" |
+#include "ui/gl/gl_surface.h" |
+#include "ui/gl/gl_version_info.h" |
+#include "ui/gl/scoped_make_current.h" |
+#include "ui/gl/test/gl_surface_test_support.h" |
+ |
+#if defined(OS_MACOSX) |
+#include <CoreFoundation/CoreFoundation.h> |
+#include "ui/gl/gl_image_io_surface.h" |
+#endif |
+ |
+#if defined(OS_ANDROID) |
+#include <android/native_window_jni.h> |
+#include "base/android/jni_android.h" |
+#include "ui/gl/android/scoped_java_surface.h" |
+#include "ui/gl/android/surface_texture.h" |
+#include "ui/gl/gl_image_surface_texture.h" |
+#endif |
+ |
+namespace gfx { |
+namespace { |
+ |
+enum class GLImageType { |
Daniele Castagna
2015/09/22 15:55:32
Have you considered having one test fixture for ea
reveman
2015/09/24 00:31:42
Latest patch implements this using a test template
|
+ SHARED_MEMORY, |
+ REF_COUNTED_MEMORY, |
+ IO_SURFACE, |
+ SURFACE_TEXTURE, |
+ OZONE_NATIVE_PIXMAP |
+}; |
+ |
+#define SHADER(Src) #Src |
+ |
+// clang-format off |
+ |
+const char kVertexShader[] = SHADER( |
+ uniform vec2 texScale; |
+ attribute vec2 a_position; |
+ attribute vec2 a_texCoord; |
+ varying vec2 v_texCoord; |
+ void main() { |
+ gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0); |
+ v_texCoord = vec2(a_texCoord.x * texScale.x, a_texCoord.y * texScale.y); |
+ } |
+); |
+ |
+const char kFragmentShader[] = SHADER( |
+ uniform SamplerType a_texture; |
+ varying vec2 v_texCoord; |
+ void main() { |
+ gl_FragColor = TextureLookup(a_texture, v_texCoord); |
+ } |
+); |
+ |
+// clang-format on |
+ |
+const char kTexture2DFragmentShaderPrefix[] = |
+ "#define SamplerType sampler2D\n" |
+ "#define TextureLookup texture2D\n"; |
+ |
+const char kTextureRectangleFragmentShaderPrefix[] = |
+ "#extension GL_ARB_texture_rectangle : require\n" |
+ "#define SamplerType sampler2DRect\n" |
+ "#define TextureLookup texture2DRect\n"; |
+ |
+const char kTextureExternalFragmentShaderPrefix[] = |
+ "#extension GL_OES_EGL_image_external : require\n" |
+ "#define SamplerType samplerExternalOES\n" |
+ "#define TextureLookup texture2D\n"; |
+ |
+GLuint LoadShader(GLenum type, const char* const src) { |
+ GLuint shader = glCreateShader(type); |
+ glShaderSource(shader, 1, &src, nullptr); |
+ glCompileShader(shader); |
+ GLint compiled = 0; |
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); |
+ DCHECK(compiled); |
+ return shader; |
+} |
+ |
+class GLImageTest : public testing::TestWithParam<GLImageType> { |
+ public: |
+ // Overridden from testing::Test: |
+ void SetUp() override { |
+#if defined(USE_OZONE) |
+ // On Ozone, the backend initializes the event system using a UI thread. |
+ base::MessageLoopForUI main_loop; |
+#endif |
+ |
+ std::vector<GLImplementation> allowed_impls; |
+ GetAllowedGLImplementations(&allowed_impls); |
+ DCHECK(!allowed_impls.empty()); |
+ |
+ GLImplementation impl = allowed_impls[0]; |
+ GLSurfaceTestSupport::InitializeOneOffImplementation(impl); |
+ |
+ surface_ = GLSurface::CreateOffscreenGLSurface(Size()); |
+ context_ = GLContext::CreateGLContext(nullptr, surface_.get(), |
+ PreferIntegratedGpu); |
+ |
+ ui::ScopedMakeCurrent scoped_make_current(context_.get(), surface_.get()); |
+ |
+ bool has_texture_format_bgra8888 = |
+ context_->HasExtension("GL_APPLE_texture_format_BGRA8888") || |
+ context_->HasExtension("GL_EXT_texture_format_BGRA8888") || |
+ !context_->GetVersionInfo()->is_es; |
+ if (!SK_B32_SHIFT && has_texture_format_bgra8888) { |
+ preferred_format_ = BufferFormat::BGRA_8888; |
+ preferred_internal_format_ = GL_BGRA_EXT; |
+ } |
+ |
+ glGenTextures(1, &color_texture_); |
+ glBindTexture(GL_TEXTURE_2D, color_texture_); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
+ // Create a 1024x1024 color buffer. |
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, |
+ GL_UNSIGNED_BYTE, nullptr); |
+ glBindTexture(GL_TEXTURE_2D, 0); |
+ glGenFramebuffersEXT(1, &framebuffer_); |
+ glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer_); |
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
+ GL_TEXTURE_2D, color_texture_, 0); |
+ DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), |
+ glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); |
+ |
+ vertex_shader_ = LoadShader(GL_VERTEX_SHADER, kVertexShader); |
+ bool is_gles = context_->GetVersionInfo()->is_es; |
+ fragment_shader_ = |
+ LoadShader(GL_FRAGMENT_SHADER, |
+ base::StringPrintf("%s%s%s", TextureFragmentShaderPrefix(), |
+ is_gles ? "precision mediump float;" : "", |
+ kFragmentShader) |
+ .c_str()); |
+ program_ = glCreateProgram(); |
+ glAttachShader(program_, vertex_shader_); |
+ glAttachShader(program_, fragment_shader_); |
+ glBindAttribLocation(program_, 0, "a_position"); |
+ glBindAttribLocation(program_, 1, "a_texCoord"); |
+ glLinkProgram(program_); |
+ GLint linked = -1; |
+ glGetProgramiv(program_, GL_LINK_STATUS, &linked); |
+ DCHECK_NE(linked, 0); |
+ glUseProgram(program_); |
+ sampler_location_ = glGetUniformLocation(program_, "a_texture"); |
+ DCHECK_NE(sampler_location_, -1); |
+ glUniform1i(sampler_location_, 0); |
+ texture_scale_location_ = glGetUniformLocation(program_, "texScale"); |
+ DCHECK_NE(texture_scale_location_, -1); |
+ glUniform2f(texture_scale_location_, 1.f, 1.0f); |
+ |
+ glGenBuffersARB(1, &vertex_buffer_); |
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_); |
+ // clang-format off |
+ static GLfloat vertices[] = { |
+ -1.f, -1.f, 0.f, 0.f, |
+ 1.f, -1.f, 1.f, 0.f, |
+ -1.f, 1.f, 0.f, 1.f, |
+ 1.f, 1.f, 1.f, 1.f |
+ }; |
+ // clang-format on |
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, 0); |
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, |
+ reinterpret_cast<void*>(sizeof(GLfloat) * 2)); |
+ glEnableVertexAttribArray(0); |
+ glEnableVertexAttribArray(1); |
+ } |
+ void TearDown() override { |
+ { |
+ ui::ScopedMakeCurrent scoped_make_current(context_.get(), surface_.get()); |
+ |
+ glDeleteProgram(program_); |
+ glDeleteShader(vertex_shader_); |
+ glDeleteShader(fragment_shader_); |
+ glBindBuffer(GL_ARRAY_BUFFER, 0); |
+ glDeleteBuffersARB(1, &vertex_buffer_); |
+ glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
+ glDeleteFramebuffersEXT(1, &framebuffer_); |
+ glDeleteTextures(1, &color_texture_); |
+ } |
+ |
+ context_ = nullptr; |
+ surface_ = nullptr; |
+ |
+ ClearGLBindings(); |
+ } |
+ |
+ protected: |
+ scoped_refptr<GLImage> CreateSolidColorImage(const Size& size, |
+ unsigned internalformat, |
+ BufferFormat format, |
+ SkColor color) { |
+ switch (GetParam()) { |
+ case GLImageType::SHARED_MEMORY: { |
+ DCHECK_EQ(NumberOfPlanesForBufferFormat(format), 1u); |
+ base::SharedMemory shared_memory; |
+ if (!shared_memory.CreateAndMapAnonymous( |
+ BufferSizeForBufferFormat(size, format))) { |
+ return nullptr; |
+ } |
+ ClearDataToSolidColor( |
+ size, format, |
+ static_cast<int>(RowSizeForBufferFormat(size.width(), format, 0)), |
+ reinterpret_cast<uint8_t*>(shared_memory.memory()), color); |
+ |
+ scoped_refptr<GLImageSharedMemory> image( |
+ new GLImageSharedMemory(size, internalformat)); |
+ if (!image->Initialize( |
+ base::SharedMemory::DuplicateHandle(shared_memory.handle()), |
+ NextGenericSharedMemoryId(), format)) { |
+ return nullptr; |
+ } |
+ return image; |
+ } |
+ case GLImageType::REF_COUNTED_MEMORY: { |
+ DCHECK_EQ(NumberOfPlanesForBufferFormat(format), 1u); |
+ std::vector<uint8_t> data(BufferSizeForBufferFormat(size, format), 0); |
+ scoped_refptr<base::RefCountedBytes> bytes( |
+ new base::RefCountedBytes(data)); |
+ ClearDataToSolidColor( |
+ size, format, |
+ static_cast<int>(RowSizeForBufferFormat(size.width(), format, 0)), |
+ &bytes->data().front(), color); |
+ |
+ scoped_refptr<GLImageRefCountedMemory> image( |
+ new GLImageRefCountedMemory(size, internalformat)); |
+ if (!image->Initialize(bytes.get(), format)) |
+ return nullptr; |
+ return image; |
+ } |
+ case GLImageType::IO_SURFACE: { |
+#if defined(OS_MACOSX) |
+ DCHECK(format == BufferFormat::BGRA_8888); |
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> properties( |
+ CFDictionaryCreateMutable(kCFAllocatorDefault, 0, |
+ &kCFTypeDictionaryKeyCallBacks, |
+ &kCFTypeDictionaryValueCallBacks)); |
+ int32_t width = size.width(); |
+ base::ScopedCFTypeRef<CFNumberRef> cf_width( |
+ CFNumberCreate(nullptr, kCFNumberSInt32Type, &width)); |
+ CFDictionaryAddValue(properties, kIOSurfaceWidth, cf_width.get()); |
+ int32_t height = size.height(); |
+ base::ScopedCFTypeRef<CFNumberRef> cf_height( |
+ CFNumberCreate(nullptr, kCFNumberSInt32Type, &height)); |
+ CFDictionaryAddValue(properties, kIOSurfaceHeight, cf_height.get()); |
+ int32_t pixel_format = 'BGRA'; |
+ base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format( |
+ CFNumberCreate(nullptr, kCFNumberSInt32Type, &pixel_format)); |
+ CFDictionaryAddValue(properties, kIOSurfacePixelFormat, |
+ cf_pixel_format.get()); |
+ int32_t bytes_per_element = 4; |
+ base::ScopedCFTypeRef<CFNumberRef> cf_bytes_per_element( |
+ CFNumberCreate(nullptr, kCFNumberSInt32Type, &bytes_per_element)); |
+ CFDictionaryAddValue(properties, kIOSurfaceBytesPerElement, |
+ cf_bytes_per_element.get()); |
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface( |
+ IOSurfaceCreate(properties)); |
+ DCHECK(io_surface); |
+ IOReturn status = IOSurfaceLock(io_surface, 0, nullptr); |
+ DCHECK_EQ(status, kIOReturnSuccess); |
+ ClearDataToSolidColor( |
+ size, format, static_cast<int>(IOSurfaceGetBytesPerRow(io_surface)), |
+ reinterpret_cast<uint8_t*>(IOSurfaceGetBaseAddress(io_surface)), |
+ color); |
+ IOSurfaceUnlock(io_surface, 0, nullptr); |
+ |
+ scoped_refptr<GLImageIOSurface> image( |
+ new GLImageIOSurface(size, internalformat)); |
+ if (!image->Initialize(io_surface, NextGenericSharedMemoryId(), |
+ format)) { |
+ return nullptr; |
+ } |
+ return image; |
+#else |
+ NOTREACHED(); |
+ return nullptr; |
+#endif |
+ } |
+ case GLImageType::SURFACE_TEXTURE: { |
+#if defined(OS_ANDROID) |
+ const int kDummyTextureId = 0; |
+ scoped_refptr<SurfaceTexture> surface_texture = |
+ SurfaceTexture::Create(kDummyTextureId); |
+ DCHECK(surface_texture); |
+ DCHECK(format == BufferFormat::RGBA_8888); |
+ ScopedJavaSurface surface(surface_texture.get()); |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ ANativeWindow* native_window = |
+ ANativeWindow_fromSurface(env, surface.j_surface().obj()); |
+ ANativeWindow_setBuffersGeometry(native_window, size.width(), |
+ size.height(), |
+ WINDOW_FORMAT_RGBA_8888); |
+ ANativeWindow_Buffer buffer; |
+ int rv = ANativeWindow_lock(native_window, &buffer, nullptr); |
+ DCHECK_EQ(rv, 0); |
+ ClearDataToSolidColor(size, format, buffer.stride, |
+ reinterpret_cast<uint8_t*>(buffer.bits), color); |
+ ANativeWindow_unlockAndPost(native_window); |
+ |
+ scoped_refptr<GLImageSurfaceTexture> image( |
+ new GLImageSurfaceTexture(size)); |
+ if (!image->Initialize(surface_texture.get())) |
+ return nullptr; |
+ return image; |
+#else |
+ NOTREACHED(); |
+ return nullptr; |
+#endif |
+ } |
+ case GLImageType::OZONE_NATIVE_PIXMAP: |
+ NOTREACHED(); |
+ return nullptr; |
+ } |
+ NOTREACHED(); |
+ return nullptr; |
+ } |
+ |
+ GLenum GetTextureTarget() { |
+ switch (GetParam()) { |
+ case GLImageType::SHARED_MEMORY: |
+ case GLImageType::REF_COUNTED_MEMORY: |
+ return GL_TEXTURE_2D; |
+ case GLImageType::IO_SURFACE: |
+ return GL_TEXTURE_RECTANGLE_ARB; |
+ case GLImageType::SURFACE_TEXTURE: |
+ case GLImageType::OZONE_NATIVE_PIXMAP: |
+ return GL_TEXTURE_EXTERNAL_OES; |
+ } |
+ NOTREACHED(); |
+ return GL_TEXTURE_2D; |
+ } |
+ |
+ const char* TextureFragmentShaderPrefix() { |
+ switch (GetParam()) { |
+ case GLImageType::SHARED_MEMORY: |
+ case GLImageType::REF_COUNTED_MEMORY: |
+ return kTexture2DFragmentShaderPrefix; |
+ case GLImageType::IO_SURFACE: |
+ return kTextureRectangleFragmentShaderPrefix; |
+ case GLImageType::SURFACE_TEXTURE: |
+ case GLImageType::OZONE_NATIVE_PIXMAP: |
+ return kTextureExternalFragmentShaderPrefix; |
+ } |
+ NOTREACHED(); |
+ return nullptr; |
+ } |
+ |
+ Vector2dF GetTextureScale(Size size) { |
+ switch (GetParam()) { |
+ case GLImageType::SHARED_MEMORY: |
+ case GLImageType::REF_COUNTED_MEMORY: |
+ case GLImageType::SURFACE_TEXTURE: |
+ case GLImageType::OZONE_NATIVE_PIXMAP: |
+ return Vector2dF(1.f, 1.f); |
+ case GLImageType::IO_SURFACE: |
+ return Vector2dF(size.width(), size.height()); |
+ } |
+ NOTREACHED(); |
+ return Vector2dF(); |
+ } |
+ |
+ void DrawTexture(Size size) { |
+ Vector2dF texture_scale = GetTextureScale(size); |
+ glUniform2f(texture_scale_location_, texture_scale.x(), texture_scale.y()); |
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
+ } |
+ |
+ GenericSharedMemoryId NextGenericSharedMemoryId() { |
+ return GenericSharedMemoryId(next_generic_shared_memory_id_++); |
+ } |
+ |
+ bool CheckPixels(int x, int y, int width, int height, SkColor color) { |
+ int size = width * height * 4; |
+ scoped_ptr<uint8_t[]> pixels(new uint8_t[size]); |
+ const uint8_t kCheckClearValue = 123u; |
+ memset(pixels.get(), kCheckClearValue, size); |
+ glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); |
+ uint8_t expected_color[] = { |
+ SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), |
+ SkColorGetA(color), |
+ }; |
+ int bad_count = 0; |
+ for (int yy = 0; yy < height; ++yy) { |
+ for (int xx = 0; xx < width; ++xx) { |
+ int offset = yy * width * 4 + xx * 4; |
+ for (int jj = 0; jj < 4; ++jj) { |
+ uint8_t actual = pixels[offset + jj]; |
+ uint8_t expected = expected_color[jj]; |
+ EXPECT_EQ(expected, actual) << " at " << (xx + x) << ", " << (yy + y) |
+ << " channel " << jj; |
+ bad_count += actual != expected; |
+ // Exit early just so we don't spam the log but we print enough to |
+ // hopefully make it easy to diagnose the issue. |
+ if (bad_count > 16) |
+ return false; |
+ } |
+ } |
+ } |
+ |
+ return !bad_count; |
+ } |
+ |
+ void ClearDataToSolidColor(const Size& size, |
+ BufferFormat format, |
+ int stride, |
+ uint8_t* data, |
+ SkColor color) { |
+ switch (format) { |
+ case BufferFormat::RGBA_8888: |
+ for (int y = 0; y < size.height(); ++y) { |
+ for (int x = 0; x < size.width(); ++x) { |
+ data[y * stride + x * 4 + 0] = SkColorGetR(color); |
+ data[y * stride + x * 4 + 1] = SkColorGetG(color); |
+ data[y * stride + x * 4 + 2] = SkColorGetB(color); |
+ data[y * stride + x * 4 + 3] = SkColorGetA(color); |
+ } |
+ } |
+ return; |
+ case BufferFormat::BGRA_8888: |
+ for (int y = 0; y < size.height(); ++y) { |
+ for (int x = 0; x < size.width(); ++x) { |
+ data[y * stride + x * 4 + 0] = SkColorGetB(color); |
+ data[y * stride + x * 4 + 1] = SkColorGetG(color); |
+ data[y * stride + x * 4 + 2] = SkColorGetR(color); |
+ data[y * stride + x * 4 + 3] = SkColorGetA(color); |
+ } |
+ } |
+ return; |
+ case BufferFormat::ATC: |
+ case BufferFormat::ATCIA: |
+ case BufferFormat::DXT1: |
+ case BufferFormat::DXT5: |
+ case BufferFormat::ETC1: |
+ case BufferFormat::R_8: |
+ case BufferFormat::RGBA_4444: |
+ case BufferFormat::BGRX_8888: |
+ case BufferFormat::UYVY_422: |
+ case BufferFormat::YUV_420_BIPLANAR: |
+ case BufferFormat::YUV_420: |
+ NOTREACHED(); |
+ return; |
+ } |
+ NOTREACHED(); |
+ } |
+ |
+ scoped_refptr<GLContext> context_; |
+ scoped_refptr<GLSurface> surface_; |
+ BufferFormat preferred_format_ = BufferFormat::RGBA_8888; |
+ GLenum preferred_internal_format_ = GL_RGBA; |
+ GLuint color_texture_ = 0; |
+ GLuint framebuffer_ = 0; |
+ GLuint vertex_shader_ = 0; |
+ GLuint fragment_shader_ = 0; |
+ GLuint program_ = 0; |
+ GLuint vertex_buffer_ = 0; |
+ GLint sampler_location_ = -1; |
+ GLint texture_scale_location_ = -1; |
+ int next_generic_shared_memory_id_ = 1; |
+}; |
+ |
+TEST_P(GLImageTest, CopyTexSubImage) { |
Daniele Castagna
2015/09/22 15:55:32
Can you spend few words here describing CopyTexSub
reveman
2015/09/24 00:31:42
Added some more comments to latest patch but I'd r
|
+ ui::ScopedMakeCurrent scoped_make_current(context_.get(), surface_.get()); |
+ |
+ const Size image_size(256, 256); |
+ scoped_refptr<GLImage> image = CreateSolidColorImage( |
+ image_size, preferred_internal_format_, preferred_format_, SK_ColorGREEN); |
+ if (!image) |
Daniele Castagna
2015/09/22 15:55:32
When would this happen?
reveman
2015/09/24 00:31:42
Made it a requirement for this to be supported by
|
+ return; |
+ |
+ GLenum target = GetTextureTarget(); |
+ GLuint texture = 0; |
+ glGenTextures(1, &texture); |
+ glBindTexture(target, texture); |
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
+ glTexImage2D(target, 0, preferred_internal_format_, image_size.width(), |
+ image_size.height(), 0, preferred_internal_format_, |
+ GL_UNSIGNED_BYTE, nullptr); |
+ |
+ // Copy image to |texture|. If supported, check that |texture| contains |
+ // the correct result. |
+ if (image->CopyTexSubImage(target, Point(), Rect(image_size))) { |
Daniele Castagna
2015/09/22 15:55:32
Is it OK not to support CopyTexSubImage?
If that i
reveman
2015/09/24 00:31:42
Yes.
|
+ glViewport(0, 0, image_size.width(), image_size.height()); |
+ DrawTexture(image_size); |
+ CheckPixels(0, 0, image_size.width(), image_size.height(), SK_ColorGREEN); |
+ } |
+ |
+ glDeleteTextures(1, &texture); |
+ image->Destroy(true); |
+} |
+ |
+static const GLImageType kGLImageTypes[] = { |
+ GLImageType::SHARED_MEMORY, GLImageType::REF_COUNTED_MEMORY, |
+#if defined(OS_MACOSX) |
+ GLImageType::IO_SURFACE, |
+#endif |
+#if defined(OS_ANDROID) |
+ GLImageType::SURFACE_TEXTURE, |
+#endif |
+}; |
+ |
+INSTANTIATE_TEST_CASE_P(GLImageTests, |
+ GLImageTest, |
+ ::testing::ValuesIn(kGLImageTypes)); |
+ |
+} // namespace |
+} // namespace gfx |