1 // Copyright 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 #include "cc/scheduler/texture_uploader.h" 6 7 #include "cc/base/util.h" 8 #include "cc/resources/prioritized_resource.h" 9 #include "cc/test/test_web_graphics_context_3d.h" 10 #include "testing/gmock/include/gmock/gmock.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 #include "third_party/khronos/GLES2/gl2.h" 13 #include "third_party/khronos/GLES2/gl2ext.h" 14 15 using WebKit::WGC3Denum; 16 using WebKit::WGC3Dint; 17 using WebKit::WGC3Dsizei; 18 using WebKit::WebGLId; 19 using WebKit::WGC3Duint; 20 21 namespace cc { 22 namespace { 23 24 class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D { 25 public: 26 TestWebGraphicsContext3DTextureUpload() 27 : result_available_(0), 28 unpack_alignment_(4) {} 29 30 virtual void pixelStorei(WGC3Denum pname, WGC3Dint param) OVERRIDE { 31 switch (pname) { 32 case GL_UNPACK_ALIGNMENT: 33 // Param should be a power of two <= 8. 34 EXPECT_EQ(0, param & (param - 1)); 35 EXPECT_GE(8, param); 36 switch (param) { 37 case 1: 38 case 2: 39 case 4: 40 case 8: 41 unpack_alignment_ = param; 42 break; 43 default: 44 break; 45 } 46 break; 47 default: 48 break; 49 } 50 } 51 52 virtual void getQueryObjectuivEXT(WebGLId, WGC3Denum type, WGC3Duint* value) 53 OVERRIDE { 54 switch (type) { 55 case GL_QUERY_RESULT_AVAILABLE_EXT: 56 *value = result_available_; 57 break; 58 default: 59 *value = 0; 60 break; 61 } 62 } 63 64 virtual void texSubImage2D(WGC3Denum target, 65 WGC3Dint level, 66 WGC3Dint xoffset, 67 WGC3Dint yoffset, 68 WGC3Dsizei width, 69 WGC3Dsizei height, 70 WGC3Denum format, 71 WGC3Denum type, 72 const void* pixels) OVERRIDE { 73 EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); 74 EXPECT_EQ(0, level); 75 EXPECT_LE(0, width); 76 EXPECT_LE(0, height); 77 EXPECT_LE(0, xoffset); 78 EXPECT_LE(0, yoffset); 79 EXPECT_LE(0, width); 80 EXPECT_LE(0, height); 81 82 // Check for allowed format/type combination. 83 unsigned int bytes_per_pixel = 0; 84 switch (format) { 85 case GL_ALPHA: 86 EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); 87 bytes_per_pixel = 1; 88 break; 89 case GL_RGB: 90 EXPECT_NE(static_cast<unsigned>(GL_UNSIGNED_SHORT_4_4_4_4), type); 91 EXPECT_NE(static_cast<unsigned>(GL_UNSIGNED_SHORT_5_5_5_1), type); 92 switch (type) { 93 case GL_UNSIGNED_BYTE: 94 bytes_per_pixel = 3; 95 break; 96 case GL_UNSIGNED_SHORT_5_6_5: 97 bytes_per_pixel = 2; 98 break; 99 } 100 break; 101 case GL_RGBA: 102 EXPECT_NE(static_cast<unsigned>(GL_UNSIGNED_SHORT_5_6_5), type); 103 switch (type) { 104 case GL_UNSIGNED_BYTE: 105 bytes_per_pixel = 4; 106 break; 107 case GL_UNSIGNED_SHORT_4_4_4_4: 108 bytes_per_pixel = 2; 109 break; 110 case GL_UNSIGNED_SHORT_5_5_5_1: 111 bytes_per_pixel = 2; 112 break; 113 } 114 break; 115 case GL_LUMINANCE: 116 EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); 117 bytes_per_pixel = 1; 118 break; 119 case GL_LUMINANCE_ALPHA: 120 EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); 121 bytes_per_pixel = 2; 122 break; 123 } 124 125 // If NULL, we aren't checking texture contents. 126 if (pixels == NULL) 127 return; 128 129 const uint8* bytes = static_cast<const uint8*>(pixels); 130 // We'll expect the first byte of every row to be 0x1, and the last byte to 131 // be 0x2. 132 const unsigned int stride = 133 RoundUp(bytes_per_pixel * width, unpack_alignment_); 134 for (WGC3Dsizei row = 0; row < height; ++row) { 135 const uint8* row_bytes = 136 bytes + (xoffset * bytes_per_pixel + (yoffset + row) * stride); 137 EXPECT_EQ(0x1, row_bytes[0]); 138 EXPECT_EQ(0x2, row_bytes[width * bytes_per_pixel - 1]); 139 } 140 } 141 142 void SetResultAvailable(unsigned result_available) { 143 result_available_ = result_available; 144 } 145 146 private: 147 unsigned result_available_; 148 unsigned unpack_alignment_; 149 150 DISALLOW_COPY_AND_ASSIGN(TestWebGraphicsContext3DTextureUpload); 151 }; 152 153 void UploadTexture(TextureUploader* uploader, 154 WGC3Denum format, 155 gfx::Size size, 156 const uint8* data) { 157 uploader->Upload(data, 158 gfx::Rect(size), 159 gfx::Rect(size), 160 gfx::Vector2d(), 161 format, 162 size); 163 } 164 165 TEST(TextureUploaderTest, NumBlockingUploads) { 166 scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( 167 new TestWebGraphicsContext3DTextureUpload); 168 scoped_ptr<TextureUploader> uploader = 169 TextureUploader::Create(fake_context.get(), false, false); 170 171 fake_context->SetResultAvailable(0); 172 EXPECT_EQ(0u, uploader->NumBlockingUploads()); 173 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 174 EXPECT_EQ(1u, uploader->NumBlockingUploads()); 175 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 176 EXPECT_EQ(2u, uploader->NumBlockingUploads()); 177 178 fake_context->SetResultAvailable(1); 179 EXPECT_EQ(0u, uploader->NumBlockingUploads()); 180 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 181 EXPECT_EQ(0u, uploader->NumBlockingUploads()); 182 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 183 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 184 EXPECT_EQ(0u, uploader->NumBlockingUploads()); 185 } 186 187 TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) { 188 scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( 189 new TestWebGraphicsContext3DTextureUpload); 190 scoped_ptr<TextureUploader> uploader = 191 TextureUploader::Create(fake_context.get(), false, false); 192 193 fake_context->SetResultAvailable(0); 194 EXPECT_EQ(0u, uploader->NumBlockingUploads()); 195 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 196 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 197 EXPECT_EQ(2u, uploader->NumBlockingUploads()); 198 199 uploader->MarkPendingUploadsAsNonBlocking(); 200 EXPECT_EQ(0u, uploader->NumBlockingUploads()); 201 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 202 EXPECT_EQ(1u, uploader->NumBlockingUploads()); 203 204 fake_context->SetResultAvailable(1); 205 EXPECT_EQ(0u, uploader->NumBlockingUploads()); 206 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); 207 uploader->MarkPendingUploadsAsNonBlocking(); 208 EXPECT_EQ(0u, uploader->NumBlockingUploads()); 209 } 210 211 TEST(TextureUploaderTest, UploadContentsTest) { 212 scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( 213 new TestWebGraphicsContext3DTextureUpload); 214 scoped_ptr<TextureUploader> uploader = 215 TextureUploader::Create(fake_context.get(), false, false); 216 uint8 buffer[256 * 256 * 4]; 217 218 // Upload a tightly packed 256x256 RGBA texture. 219 memset(buffer, 0, sizeof(buffer)); 220 for (int i = 0; i < 256; ++i) { 221 // Mark the beginning and end of each row, for the test. 222 buffer[i * 4 * 256] = 0x1; 223 buffer[(i + 1) * 4 * 256 - 1] = 0x2; 224 } 225 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(256, 256), buffer); 226 227 // Upload a tightly packed 41x43 RGBA texture. 228 memset(buffer, 0, sizeof(buffer)); 229 for (int i = 0; i < 43; ++i) { 230 // Mark the beginning and end of each row, for the test. 231 buffer[i * 4 * 41] = 0x1; 232 buffer[(i + 1) * 4 * 41 - 1] = 0x2; 233 } 234 UploadTexture(uploader.get(), GL_RGBA, gfx::Size(41, 43), buffer); 235 236 // Upload a tightly packed 82x86 LUMINANCE texture. 237 memset(buffer, 0, sizeof(buffer)); 238 for (int i = 0; i < 86; ++i) { 239 // Mark the beginning and end of each row, for the test. 240 buffer[i * 1 * 82] = 0x1; 241 buffer[(i + 1) * 82 - 1] = 0x2; 242 } 243 UploadTexture(uploader.get(), GL_LUMINANCE, gfx::Size(82, 86), buffer); 244 } 245 246 } // namespace 247 } // namespace cc 248