aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--dm/DMGpuTestProcs.cpp3
-rw-r--r--gn/tests.gni1
-rw-r--r--src/gpu/mtl/GrMtlGpu.h35
-rw-r--r--src/gpu/mtl/GrMtlGpu.mm180
-rw-r--r--src/gpu/mtl/GrMtlUtil.h5
-rw-r--r--src/gpu/mtl/GrMtlUtil.mm4
-rw-r--r--tests/GrTestingBackendTextureUploadTest.cpp81
-rw-r--r--tests/Test.h4
-rw-r--r--tests/TestUtils.cpp29
-rw-r--r--tests/TestUtils.h8
-rw-r--r--tests/VkUploadPixelsTests.cpp31
11 files changed, 321 insertions, 60 deletions
diff --git a/dm/DMGpuTestProcs.cpp b/dm/DMGpuTestProcs.cpp
index abae62806f..ae8c7ab689 100644
--- a/dm/DMGpuTestProcs.cpp
+++ b/dm/DMGpuTestProcs.cpp
@@ -19,6 +19,9 @@ bool IsGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
bool IsVulkanContextType(sk_gpu_test::GrContextFactory::ContextType type) {
return kVulkan_GrBackend == GrContextFactory::ContextTypeBackend(type);
}
+bool IsMetalContextType(sk_gpu_test::GrContextFactory::ContextType type) {
+ return kMetal_GrBackend == GrContextFactory::ContextTypeBackend(type);
+}
bool IsRenderingGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
return IsGLContextType(type) && GrContextFactory::IsRenderingContext(type);
}
diff --git a/gn/tests.gni b/gn/tests.gni
index b98fe46417..15a266b0ed 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -102,6 +102,7 @@ tests_sources = [
"$_tests/GrShapeTest.cpp",
"$_tests/GrSKSLPrettyPrintTest.cpp",
"$_tests/GrSurfaceTest.cpp",
+ "$_tests/GrTestingBackendTextureUploadTest.cpp",
"$_tests/GrTextureMipMapInvalidationTest.cpp",
"$_tests/GrTRecorderTest.cpp",
"$_tests/HashTest.cpp",
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index be922e5fdb..8a68b763eb 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -39,6 +39,23 @@ public:
kSkip_SyncQueue
};
+#ifdef GR_TEST_UTILS
+ GrBackendTexture createTestingOnlyBackendTexture(const void* pixels, int w, int h,
+ GrPixelConfig config, bool isRT,
+ GrMipMapped) override;
+
+ bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
+
+ void deleteTestingOnlyBackendTexture(const GrBackendTexture&) override;
+
+ GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType,
+ GrSRGBEncoded) override;
+
+ void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
+
+ void testingOnly_flushGpuAndSync() override;
+#endif
+
bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
GrSurface* src, GrSurfaceOrigin srcOrigin,
const SkIRect& srcRect,
@@ -135,21 +152,9 @@ private:
void clearStencil(GrRenderTarget* target, int clearValue) override {}
#if GR_TEST_UTILS
- GrBackendTexture createTestingOnlyBackendTexture(const void* pixels, int w, int h,
- GrPixelConfig config, bool isRT,
- GrMipMapped) override {
- return GrBackendTexture();
- }
- bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override { return false; }
- void deleteTestingOnlyBackendTexture(const GrBackendTexture&) override {}
-
- GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType,
- GrSRGBEncoded) override {
- return {};
- }
- void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override {}
-
- void testingOnly_flushGpuAndSync() override {}
+ bool createTestingOnlyMtlTextureInfo(GrPixelConfig config, int w, int h, bool texturable,
+ bool renderable, GrMipMapped mipMapped,
+ const void* srcData, GrMtlTextureInfo* info);
#endif
sk_sp<GrMtlCaps> fMtlCaps;
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 41ed23e3a5..0295659b36 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -95,21 +95,6 @@ GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options,
fCaps = fMtlCaps;
fCmdBuffer = [fQueue commandBuffer];
-
- MTLTextureDescriptor* txDesc = [[MTLTextureDescriptor alloc] init];
- txDesc.textureType = MTLTextureType3D;
- txDesc.height = 64;
- txDesc.width = 64;
- txDesc.depth = 64;
- txDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
- txDesc.arrayLength = 1;
- txDesc.mipmapLevelCount = 1;
- id<MTLTexture> testTexture = [fDevice newTextureWithDescriptor:txDesc];
- // To get ride of unused var warning
- int width = [testTexture width];
- SkDebugf("width: %d\n", width);
- // Unused queue warning fix
- SkDebugf("ptr to queue: %p\n", fQueue);
}
void GrMtlGpu::submitCommandBuffer(SyncQueue sync) {
@@ -364,6 +349,171 @@ sk_sp<GrRenderTarget> GrMtlGpu::onWrapBackendTextureAsRenderTarget(
return GrMtlRenderTarget::MakeWrappedRenderTarget(this, surfDesc, mtlTexture);
}
+#ifdef GR_TEST_UTILS
+bool GrMtlGpu::createTestingOnlyMtlTextureInfo(GrPixelConfig config, int w, int h, bool texturable,
+ bool renderable, GrMipMapped mipMapped,
+ const void* srcData, GrMtlTextureInfo* info) {
+ SkASSERT(texturable || renderable);
+ if (!texturable) {
+ SkASSERT(GrMipMapped::kNo == mipMapped);
+ SkASSERT(!srcData);
+ }
+
+ MTLPixelFormat format;
+ if (!GrPixelConfigToMTLFormat(config, &format)) {
+ return false;
+ }
+ if (texturable && !fMtlCaps->isConfigTexturable(config)) {
+ return false;
+ }
+ if (renderable && !fMtlCaps->isConfigRenderable(config)) {
+ return false;
+ }
+ // Currently we don't support uploading pixel data when mipped.
+ if (srcData && GrMipMapped::kYes == mipMapped) {
+ return false;
+ }
+ if(!check_max_blit_width(w)) {
+ return false;
+ }
+
+ bool mipmapped = mipMapped == GrMipMapped::kYes ? true : false;
+ MTLTextureDescriptor* desc =
+ [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: format
+ width: w
+ height: h
+ mipmapped: mipmapped];
+ desc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
+ desc.storageMode = MTLStorageModePrivate;
+ desc.usage = texturable ? MTLTextureUsageShaderRead : 0;
+ desc.usage |= renderable ? MTLTextureUsageRenderTarget : 0;
+ id<MTLTexture> testTexture = [fDevice newTextureWithDescriptor: desc];
+
+ SkAutoTMalloc<GrColor> srcBuffer;
+ if (!srcData) {
+ srcBuffer.reset(w * h);
+ memset(srcBuffer, 0, w * h * sizeof(GrColor));
+ srcData = srcBuffer;
+ }
+ SkASSERT(srcData);
+
+ desc.storageMode = MTLStorageModeManaged;
+ id<MTLTexture> transferTexture = [fDevice newTextureWithDescriptor: desc];
+ auto colorType = GrPixelConfigToColorType(config);
+ int rowBytes = w * GrColorTypeBytesPerPixel(colorType);
+ MTLOrigin origin = MTLOriginMake(0, 0, 0);
+
+ SkASSERT(testTexture.pixelFormat == transferTexture.pixelFormat);
+ SkASSERT(testTexture.sampleCount == transferTexture.sampleCount);
+
+ id<MTLCommandBuffer> cmdBuffer = [fQueue commandBuffer];
+ id<MTLBlitCommandEncoder> blitCmdEncoder = [cmdBuffer blitCommandEncoder];
+ int currentWidth = w;
+ int currentHeight = h;
+ for (int mipLevel = 0; mipLevel < (int)testTexture.mipmapLevelCount; mipLevel++) {
+ [transferTexture replaceRegion: MTLRegionMake2D(0, 0, currentWidth, currentHeight)
+ mipmapLevel: mipLevel
+ withBytes: srcData
+ bytesPerRow: rowBytes];
+
+ [blitCmdEncoder copyFromTexture: transferTexture
+ sourceSlice: 0
+ sourceLevel: mipLevel
+ sourceOrigin: origin
+ sourceSize: MTLSizeMake(currentWidth, currentHeight, 1)
+ toTexture: testTexture
+ destinationSlice: 0
+ destinationLevel: mipLevel
+ destinationOrigin: origin];
+ currentWidth = SkTMax(1, currentWidth/2);
+ currentHeight = SkTMax(1, currentHeight/2);
+ }
+ [blitCmdEncoder endEncoding];
+ [cmdBuffer commit];
+ [cmdBuffer waitUntilCompleted];
+
+ info->fTexture = GrReleaseId(testTexture);
+ return true;
+}
+
+GrBackendTexture GrMtlGpu::createTestingOnlyBackendTexture(const void* pixels, int w, int h,
+ GrPixelConfig config, bool isRT,
+ GrMipMapped mipMapped) {
+ if (w > this->caps()->maxTextureSize() || h > this->caps()->maxTextureSize()) {
+ return GrBackendTexture();
+ }
+ GrMtlTextureInfo info;
+ if (!this->createTestingOnlyMtlTextureInfo(config, w, h, true, isRT, mipMapped, pixels,
+ &info)) {
+ return {};
+ }
+
+ GrBackendTexture backendTex(w, h, mipMapped, info);
+ backendTex.fConfig = config;
+ return backendTex;
+}
+
+bool GrMtlGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
+ SkASSERT(kMetal_GrBackend == tex.backend());
+
+ GrMtlTextureInfo info;
+ if (!tex.getMtlTextureInfo(&info)) {
+ return false;
+ }
+ id<MTLTexture> mtlTexture = GrGetMTLTexture(info.fTexture,
+ GrWrapOwnership::kBorrow_GrWrapOwnership);
+ if (!mtlTexture) {
+ return false;
+ }
+ return mtlTexture.usage & MTLTextureUsageShaderRead;
+}
+
+void GrMtlGpu::deleteTestingOnlyBackendTexture(const GrBackendTexture& tex) {
+ SkASSERT(kMetal_GrBackend == tex.fBackend);
+
+ GrMtlTextureInfo info;
+ if (tex.getMtlTextureInfo(&info)) {
+ // Adopts the metal texture so that ARC will clean it up.
+ GrGetMTLTexture(info.fTexture, GrWrapOwnership::kAdopt_GrWrapOwnership);
+ }
+}
+
+GrBackendRenderTarget GrMtlGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType ct,
+ GrSRGBEncoded srgbEncoded) {
+ if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
+ return GrBackendRenderTarget();
+ }
+ auto config = GrColorTypeToPixelConfig(ct, srgbEncoded);
+ if (kUnknown_GrPixelConfig == config) {
+ return {};
+ }
+ GrMtlTextureInfo info;
+ if (!this->createTestingOnlyMtlTextureInfo(config, w, h, false, true, GrMipMapped::kNo, nullptr,
+ &info)) {
+ return {};
+ }
+
+ GrBackendRenderTarget backendRT(w, h, 1, info);
+ backendRT.fConfig = config;
+ return backendRT;
+}
+
+void GrMtlGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
+ SkASSERT(kMetal_GrBackend == rt.fBackend);
+
+ GrMtlTextureInfo info;
+ if (rt.getMtlTextureInfo(&info)) {
+ this->testingOnly_flushGpuAndSync();
+ // Adopts the metal texture so that ARC will clean it up.
+ GrGetMTLTexture(info.fTexture, GrWrapOwnership::kAdopt_GrWrapOwnership);
+ }
+}
+
+void GrMtlGpu::testingOnly_flushGpuAndSync() {
+ this->submitCommandBuffer(kForce_SyncQueue);
+}
+#endif // GR_TEST_UTILS
+
bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
GrColorType dstColorType, void* buffer, size_t rowBytes) {
SkASSERT(surface);
diff --git a/src/gpu/mtl/GrMtlUtil.h b/src/gpu/mtl/GrMtlUtil.h
index a184bfa421..b3a7829531 100644
--- a/src/gpu/mtl/GrMtlUtil.h
+++ b/src/gpu/mtl/GrMtlUtil.h
@@ -35,6 +35,11 @@ id<MTLTexture> GrGetMTLTexture(const void* mtlTexture, GrWrapOwnership);
const void* GrGetPtrFromId(id idObject);
/**
+ * Returns a const void* to whatever the id object is pointing to. Always uses __bridge_retained.
+ */
+const void* GrReleaseId(id idObject);
+
+/**
* Returns a MTLTextureDescriptor which describes the MTLTexture. Useful when creating a duplicate
* MTLTexture without the same storage allocation.
*/
diff --git a/src/gpu/mtl/GrMtlUtil.mm b/src/gpu/mtl/GrMtlUtil.mm
index b658920191..5a58a259d4 100644
--- a/src/gpu/mtl/GrMtlUtil.mm
+++ b/src/gpu/mtl/GrMtlUtil.mm
@@ -126,6 +126,10 @@ const void* GrGetPtrFromId(id idObject) {
return (__bridge const void*)idObject;
}
+const void* GrReleaseId(id idObject) {
+ return (__bridge_retained const void*)idObject;
+}
+
MTLTextureDescriptor* GrGetMTLTextureDescriptor(id<MTLTexture> mtlTexture) {
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = mtlTexture.textureType;
diff --git a/tests/GrTestingBackendTextureUploadTest.cpp b/tests/GrTestingBackendTextureUploadTest.cpp
new file mode 100644
index 0000000000..1bdd455d67
--- /dev/null
+++ b/tests/GrTestingBackendTextureUploadTest.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+
+#include "GrGpu.h"
+#include "GrContextPriv.h"
+#include "GrTexture.h"
+#include "SkConvertPixels.h"
+#include "Test.h"
+#include "TestUtils.h"
+
+void testing_only_texture_test(skiatest::Reporter* reporter, GrContext* context, GrColorType ct,
+ bool renderTarget, bool doDataUpload, GrMipMapped mipMapped) {
+ const int kWidth = 16;
+ const int kHeight = 16;
+ SkAutoTMalloc<GrColor> srcBuffer;
+ if (doDataUpload) {
+ srcBuffer.reset(kWidth * kHeight);
+ fill_pixel_data(kWidth, kHeight, srcBuffer.get());
+ }
+ SkAutoTMalloc<GrColor> dstBuffer(kWidth * kHeight);
+
+ GrGpu* gpu = context->contextPriv().getGpu();
+
+ GrPixelConfig config = GrColorTypeToPixelConfig(ct, GrSRGBEncoded::kNo);
+ if (!gpu->caps()->isConfigTexturable(config)) {
+ return;
+ }
+
+ GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(srcBuffer,
+ kWidth,
+ kHeight,
+ config,
+ renderTarget,
+ mipMapped);
+ sk_sp<GrTexture> wrappedTex;
+ if (renderTarget) {
+ wrappedTex = gpu->wrapRenderableBackendTexture(backendTex, 1,
+ GrWrapOwnership::kAdopt_GrWrapOwnership);
+ } else {
+ wrappedTex = gpu->wrapBackendTexture(backendTex,
+ GrWrapOwnership::kAdopt_GrWrapOwnership);
+ }
+ REPORTER_ASSERT(reporter, wrappedTex);
+
+ int rowBytes = GrColorTypeBytesPerPixel(ct) * kWidth;
+ bool result = gpu->readPixels(wrappedTex.get(), 0, 0, kWidth,
+ kHeight, ct, dstBuffer, rowBytes);
+
+ if (!doDataUpload) {
+ // createTestingOnlyBackendTexture will fill the texture with 0's if no data is provided, so
+ // we set the expected result likewise.
+ srcBuffer.reset(kWidth * kHeight);
+ memset(srcBuffer, 0, kWidth * kHeight * sizeof(GrColor));
+ }
+ REPORTER_ASSERT(reporter, result);
+ REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_color(srcBuffer, dstBuffer,
+ kWidth, kHeight));
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrTestingBackendTextureUploadTest, reporter, ctxInfo) {
+ for (auto colorType: {GrColorType::kRGBA_8888, GrColorType::kBGRA_8888}) {
+ for (bool renderable: {true, false}) {
+ for (bool doDataUpload: {true, false}) {
+ testing_only_texture_test(reporter, ctxInfo.grContext(), colorType,
+ renderable, doDataUpload, GrMipMapped::kNo);
+
+ if (!doDataUpload) {
+ testing_only_texture_test(reporter, ctxInfo.grContext(), colorType,
+ renderable, doDataUpload, GrMipMapped::kYes);
+ }
+ }
+ }
+ }
+}
+
diff --git a/tests/Test.h b/tests/Test.h
index 97604a2c72..a4c931b330 100644
--- a/tests/Test.h
+++ b/tests/Test.h
@@ -129,6 +129,7 @@ typedef bool GrContextTypeFilterFn(GrContextFactoryContextType);
extern bool IsGLContextType(GrContextFactoryContextType);
extern bool IsVulkanContextType(GrContextFactoryContextType);
+extern bool IsMetalContextType(GrContextFactoryContextType);
extern bool IsRenderingGLContextType(GrContextFactoryContextType);
extern bool IsNullGLContextType(GrContextFactoryContextType);
void RunWithGPUTestContexts(GrContextTestFn*, GrContextTypeFilterFn*, Reporter*,
@@ -213,6 +214,9 @@ private:
#define DEF_GPUTEST_FOR_VULKAN_CONTEXT(name, reporter, context_info) \
DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsVulkanContextType, \
reporter, context_info, nullptr)
+#define DEF_GPUTEST_FOR_METAL_CONTEXT(name, reporter, context_info) \
+ DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsMetalContextType, \
+ reporter, context_info, nullptr)
#define REQUIRE_PDF_DOCUMENT(TEST_NAME, REPORTER) \
do { \
diff --git a/tests/TestUtils.cpp b/tests/TestUtils.cpp
index 44a78c51fb..8b611c2064 100644
--- a/tests/TestUtils.cpp
+++ b/tests/TestUtils.cpp
@@ -113,3 +113,32 @@ void test_copy_to_surface(skiatest::Reporter* reporter, GrProxyProvider* proxyPr
}
}
}
+
+void fill_pixel_data(int width, int height, GrColor* data) {
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ unsigned int red = (unsigned int)(256.f * (i / (float)width));
+ unsigned int green = (unsigned int)(256.f * (j / (float)height));
+ data[i + j * width] = GrColorPackRGBA(red - (red >> 8), green - (green >> 8),
+ 0xff, 0xff);
+ }
+ }
+}
+
+bool does_full_buffer_contain_correct_color(GrColor* srcBuffer,
+ GrColor* dstBuffer,
+ int width,
+ int height) {
+ GrColor* srcPtr = srcBuffer;
+ GrColor* dstPtr = dstBuffer;
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ if (srcPtr[i] != dstPtr[i]) {
+ return false;
+ }
+ }
+ srcPtr += width;
+ dstPtr += width;
+ }
+ return true;
+}
diff --git a/tests/TestUtils.h b/tests/TestUtils.h
index 1fe96bff7c..e89193195b 100644
--- a/tests/TestUtils.h
+++ b/tests/TestUtils.h
@@ -9,6 +9,7 @@
class GrSurfaceContext;
class GrSurfaceProxy;
+typedef uint32_t GrColor;
// Ensure that reading back from 'srcContext' as RGBA 8888 matches 'expectedPixelValues
void test_read_pixels(skiatest::Reporter*,
@@ -29,3 +30,10 @@ void test_copy_from_surface(skiatest::Reporter*, GrContext*,
// Ensure that RGBA 8888 pixels can be copied into 'dstContext'
void test_copy_to_surface(skiatest::Reporter*, GrProxyProvider*,
GrSurfaceContext* dstContext, const char* testName);
+
+// Fills data with a red-green gradient
+void fill_pixel_data(int width, int height, GrColor* data);
+
+// Checks srcBuffer and dstBuffer contain the same colors
+bool does_full_buffer_contain_correct_color(GrColor* srcBuffer, GrColor* dstBuffer, int width,
+ int height);
diff --git a/tests/VkUploadPixelsTests.cpp b/tests/VkUploadPixelsTests.cpp
index bd87d19cd1..b13de41571 100644
--- a/tests/VkUploadPixelsTests.cpp
+++ b/tests/VkUploadPixelsTests.cpp
@@ -18,40 +18,11 @@
#include "ProxyUtils.h"
#include "SkGr.h"
#include "Test.h"
+#include "TestUtils.h"
#include "vk/GrVkGpu.h"
using sk_gpu_test::GrContextFactory;
-void fill_pixel_data(int width, int height, GrColor* data) {
-
- // build red-green gradient
- for (int j = 0; j < height; ++j) {
- for (int i = 0; i < width; ++i) {
- unsigned int red = (unsigned int)(256.f*(i / (float)width));
- unsigned int green = (unsigned int)(256.f*(j / (float)height));
- data[i + j*width] = GrColorPackRGBA(red - (red>>8), green - (green>>8), 0xff, 0xff);
- }
- }
-}
-
-bool does_full_buffer_contain_correct_color(GrColor* srcBuffer,
- GrColor* dstBuffer,
- int width,
- int height) {
- GrColor* srcPtr = srcBuffer;
- GrColor* dstPtr = dstBuffer;
- for (int j = 0; j < height; ++j) {
- for (int i = 0; i < width; ++i) {
- if (srcPtr[i] != dstPtr[i]) {
- return false;
- }
- }
- srcPtr += width;
- dstPtr += width;
- }
- return true;
-}
-
void basic_texture_test(skiatest::Reporter* reporter, GrContext* context, SkColorType ct,
bool renderTarget) {
const int kWidth = 16;