1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 // This is a GPU-backend specific test. It relies on static intializers to work 9 10 #include "SkTypes.h" 11 12 #include "GrContextFactory.h" 13 #include "GrContextPriv.h" 14 #include "GrGpu.h" 15 #include "GrResourceProvider.h" 16 #include "GrSurfaceProxy.h" 17 #include "GrTexture.h" 18 #include "SkGr.h" 19 #include "SkSurface.h" 20 #include "Test.h" 21 22 using sk_gpu_test::GrContextFactory; 23 24 void fill_transfer_data(int left, int top, int width, int height, int bufferWidth, 25 GrColor* data) { 26 27 // build red-green gradient 28 for (int j = top; j < top + height; ++j) { 29 for (int i = left; i < left + width; ++i) { 30 unsigned int red = (unsigned int)(256.f*((i - left) / (float)width)); 31 unsigned int green = (unsigned int)(256.f*((j - top) / (float)height)); 32 data[i + j*bufferWidth] = GrColorPackRGBA(red - (red>>8), 33 green - (green>>8), 0xff, 0xff); 34 } 35 } 36 } 37 38 bool does_full_buffer_contain_correct_values(GrColor* srcBuffer, 39 GrColor* dstBuffer, 40 int width, 41 int height, 42 int bufferWidth, 43 int bufferHeight) { 44 GrColor* srcPtr = srcBuffer; 45 GrColor* dstPtr = dstBuffer; 46 47 for (int j = 0; j < height; ++j) { 48 for (int i = 0; i < width; ++i) { 49 if (srcPtr[i] != dstPtr[i]) { 50 return false; 51 } 52 } 53 srcPtr += bufferWidth; 54 dstPtr += bufferWidth; 55 } 56 return true; 57 } 58 59 void basic_transfer_test(skiatest::Reporter* reporter, GrContext* context, GrColorType colorType, 60 bool renderTarget) { 61 if (GrCaps::kNone_MapFlags == context->priv().caps()->mapBufferFlags()) { 62 return; 63 } 64 65 auto resourceProvider = context->priv().resourceProvider(); 66 GrGpu* gpu = context->priv().getGpu(); 67 68 // set up the data 69 const int kTextureWidth = 16; 70 const int kTextureHeight = 16; 71 #ifdef SK_BUILD_FOR_IOS 72 // UNPACK_ROW_LENGTH is broken on iOS so rowBytes needs to match data width 73 const int kBufferWidth = GrBackendApi::kOpenGL == context->backend() ? 16 : 20; 74 #else 75 const int kBufferWidth = 20; 76 #endif 77 const int kBufferHeight = 16; 78 size_t rowBytes = kBufferWidth * sizeof(GrColor); 79 SkAutoTMalloc<GrColor> srcBuffer(kBufferWidth*kBufferHeight); 80 SkAutoTMalloc<GrColor> dstBuffer(kBufferWidth*kBufferHeight); 81 82 fill_transfer_data(0, 0, kTextureWidth, kTextureHeight, kBufferWidth, srcBuffer.get()); 83 84 // create and fill transfer buffer 85 size_t size = rowBytes*kBufferHeight; 86 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(size, GrGpuBufferType::kXferCpuToGpu, 87 kDynamic_GrAccessPattern)); 88 if (!buffer) { 89 return; 90 } 91 92 void* data = buffer->map(); 93 memcpy(data, srcBuffer.get(), size); 94 buffer->unmap(); 95 96 for (auto srgbEncoding : {GrSRGBEncoded::kNo, GrSRGBEncoded::kYes}) { 97 // create texture 98 GrSurfaceDesc desc; 99 desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags; 100 desc.fWidth = kTextureWidth; 101 desc.fHeight = kTextureHeight; 102 desc.fConfig = GrColorTypeToPixelConfig(colorType, srgbEncoding); 103 desc.fSampleCnt = 1; 104 105 if (kUnknown_GrPixelConfig == desc.fConfig) { 106 SkASSERT(GrSRGBEncoded::kYes == srgbEncoding); 107 continue; 108 } 109 110 if (!context->priv().caps()->isConfigTexturable(desc.fConfig) || 111 (renderTarget && !context->priv().caps()->isConfigRenderable(desc.fConfig))) { 112 continue; 113 } 114 115 sk_sp<GrTexture> tex = resourceProvider->createTexture(desc, SkBudgeted::kNo); 116 if (!tex) { 117 continue; 118 } 119 120 ////////////////////////// 121 // transfer full data 122 123 bool result; 124 result = gpu->transferPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType, 125 buffer.get(), 0, rowBytes); 126 REPORTER_ASSERT(reporter, result); 127 128 memset(dstBuffer.get(), 0xCDCD, size); 129 result = gpu->readPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType, 130 dstBuffer.get(), rowBytes); 131 if (result) { 132 REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_values(srcBuffer, 133 dstBuffer, 134 kTextureWidth, 135 kTextureHeight, 136 kBufferWidth, 137 kBufferHeight)); 138 } 139 140 ////////////////////////// 141 // transfer partial data 142 #ifdef SK_BUILD_FOR_IOS 143 // UNPACK_ROW_LENGTH is broken on iOS so we can't do partial transfers 144 if (GrBackendApi::kOpenGL == context->backend()) { 145 continue; 146 } 147 #endif 148 const int kLeft = 2; 149 const int kTop = 10; 150 const int kWidth = 10; 151 const int kHeight = 2; 152 153 // change color of subrectangle 154 fill_transfer_data(kLeft, kTop, kWidth, kHeight, kBufferWidth, srcBuffer.get()); 155 data = buffer->map(); 156 memcpy(data, srcBuffer.get(), size); 157 buffer->unmap(); 158 159 size_t offset = sizeof(GrColor) * (kTop * kBufferWidth + kLeft); 160 result = gpu->transferPixels(tex.get(), kLeft, kTop, kWidth, kHeight, colorType, 161 buffer.get(), offset, rowBytes); 162 REPORTER_ASSERT(reporter, result); 163 164 memset(dstBuffer.get(), 0xCDCD, size); 165 result = gpu->readPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType, 166 dstBuffer.get(), rowBytes); 167 if (result) { 168 REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_values(srcBuffer, 169 dstBuffer, 170 kTextureWidth, 171 kTextureHeight, 172 kBufferWidth, 173 kBufferHeight)); 174 } 175 } 176 } 177 178 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsTest, reporter, ctxInfo) { 179 // RGBA 180 basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kRGBA_8888, false); 181 basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kRGBA_8888, true); 182 183 // BGRA 184 basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kBGRA_8888, false); 185 basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kBGRA_8888, true); 186 } 187