// Copyright 2012 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 "cc/texture_uploader.h" #include "cc/prioritized_resource.h" #include "cc/test/test_web_graphics_context_3d.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" using namespace WebKit; namespace cc { namespace { unsigned int RoundUp(unsigned int n, unsigned int mul) { return (((n - 1) / mul) * mul) + mul; } class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D { public: TestWebGraphicsContext3DTextureUpload() : m_resultAvailable(0) , m_unpackAlignment(4) { } virtual void pixelStorei(WGC3Denum pname, WGC3Dint param) { switch (pname) { case GL_UNPACK_ALIGNMENT: // param should be a power of two <= 8 EXPECT_EQ(0, param & (param - 1)); EXPECT_GE(8, param); switch (param) { case 1: case 2: case 4: case 8: m_unpackAlignment = param; break; default: break; } break; default: break; } } virtual void getQueryObjectuivEXT(WebGLId, WGC3Denum type, WGC3Duint* value) { switch (type) { case GL_QUERY_RESULT_AVAILABLE_EXT: *value = m_resultAvailable; break; default: *value = 0; break; } } virtual void texSubImage2D(WGC3Denum target, WGC3Dint level, WGC3Dint xoffset, WGC3Dint yoffset, WGC3Dsizei width, WGC3Dsizei height, WGC3Denum format, WGC3Denum type, const void* pixels) { EXPECT_EQ(GL_TEXTURE_2D, target); EXPECT_EQ(0, level); EXPECT_LE(0, width); EXPECT_LE(0, height); EXPECT_LE(0, xoffset); EXPECT_LE(0, yoffset); EXPECT_LE(0, width); EXPECT_LE(0, height); // Check for allowed format/type combination. unsigned int bytesPerPixel = 0; switch (format) { case GL_ALPHA: EXPECT_EQ(GL_UNSIGNED_BYTE, type); bytesPerPixel = 1; break; case GL_RGB: EXPECT_NE(GL_UNSIGNED_SHORT_4_4_4_4, type); EXPECT_NE(GL_UNSIGNED_SHORT_5_5_5_1, type); switch (type) { case GL_UNSIGNED_BYTE: bytesPerPixel = 3; break; case GL_UNSIGNED_SHORT_5_6_5: bytesPerPixel = 2; break; } break; case GL_RGBA: EXPECT_NE(GL_UNSIGNED_SHORT_5_6_5, type); switch (type) { case GL_UNSIGNED_BYTE: bytesPerPixel = 4; break; case GL_UNSIGNED_SHORT_4_4_4_4: bytesPerPixel = 2; break; case GL_UNSIGNED_SHORT_5_5_5_1: bytesPerPixel = 2; break; } break; case GL_LUMINANCE: EXPECT_EQ(GL_UNSIGNED_BYTE, type); bytesPerPixel = 1; break; case GL_LUMINANCE_ALPHA: EXPECT_EQ(GL_UNSIGNED_BYTE, type); bytesPerPixel = 2; break; } // If NULL, we aren't checking texture contents. if (pixels == NULL) return; const uint8* bytes = static_cast(pixels); // We'll expect the first byte of every row to be 0x1, and the last byte to be 0x2 const unsigned int stride = RoundUp(bytesPerPixel * width, m_unpackAlignment); for (WGC3Dsizei row = 0; row < height; ++row) { const uint8* rowBytes = bytes + (xoffset * bytesPerPixel + (yoffset + row) * stride); EXPECT_EQ(0x1, rowBytes[0]); EXPECT_EQ(0x2, rowBytes[width * bytesPerPixel - 1]); } } void setResultAvailable(unsigned resultAvailable) { m_resultAvailable = resultAvailable; } private: unsigned m_unpackAlignment; unsigned m_resultAvailable; }; void uploadTexture(TextureUploader* uploader, WGC3Denum format, const gfx::Size& size, const uint8* data) { uploader->upload(data, gfx::Rect(gfx::Point(0, 0), size), gfx::Rect(gfx::Point(0, 0), size), gfx::Vector2d(), format, size); } TEST(TextureUploaderTest, NumBlockingUploads) { scoped_ptr fakeContext(new TestWebGraphicsContext3DTextureUpload); scoped_ptr uploader = TextureUploader::create(fakeContext.get(), false, false); fakeContext->setResultAvailable(0); EXPECT_EQ(0, uploader->numBlockingUploads()); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); EXPECT_EQ(1, uploader->numBlockingUploads()); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); EXPECT_EQ(2, uploader->numBlockingUploads()); fakeContext->setResultAvailable(1); EXPECT_EQ(0, uploader->numBlockingUploads()); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); EXPECT_EQ(0, uploader->numBlockingUploads()); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); EXPECT_EQ(0, uploader->numBlockingUploads()); } TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) { scoped_ptr fakeContext(new TestWebGraphicsContext3DTextureUpload); scoped_ptr uploader = TextureUploader::create(fakeContext.get(), false, false); fakeContext->setResultAvailable(0); EXPECT_EQ(0, uploader->numBlockingUploads()); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); EXPECT_EQ(2, uploader->numBlockingUploads()); uploader->markPendingUploadsAsNonBlocking(); EXPECT_EQ(0, uploader->numBlockingUploads()); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); EXPECT_EQ(1, uploader->numBlockingUploads()); fakeContext->setResultAvailable(1); EXPECT_EQ(0, uploader->numBlockingUploads()); uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); uploader->markPendingUploadsAsNonBlocking(); EXPECT_EQ(0, uploader->numBlockingUploads()); } TEST(TextureUploaderTest, UploadContentsTest) { scoped_ptr fakeContext(new TestWebGraphicsContext3DTextureUpload); scoped_ptr uploader = TextureUploader::create(fakeContext.get(), false, false); uint8 buffer[256 * 256 * 4]; // Upload a tightly packed 256x256 RGBA texture. memset(buffer, 0, sizeof(buffer)); for (int i = 0; i < 256; ++i) { // Mark the beginning and end of each row, for the test. buffer[i * 4 * 256] = 0x1; buffer[(i + 1) * 4 * 256 - 1] = 0x2; } uploadTexture(uploader.get(), GL_RGBA, gfx::Size(256, 256), buffer); // Upload a tightly packed 41x43 RGBA texture. memset(buffer, 0, sizeof(buffer)); for (int i = 0; i < 43; ++i) { // Mark the beginning and end of each row, for the test. buffer[i * 4 * 41] = 0x1; buffer[(i + 1) * 4 * 41 - 1] = 0x2; } uploadTexture(uploader.get(), GL_RGBA, gfx::Size(41, 43), buffer); // Upload a tightly packed 82x86 LUMINANCE texture. memset(buffer, 0, sizeof(buffer)); for (int i = 0; i < 86; ++i) { // Mark the beginning and end of each row, for the test. buffer[i * 1 * 82] = 0x1; buffer[(i + 1) * 82 - 1] = 0x2; } uploadTexture(uploader.get(), GL_LUMINANCE, gfx::Size(82, 86), buffer); } } // namespace } // namespace cc