1 /* 2 * Copyright 2018 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 #if defined(SK_VULKAN) 13 14 #include "vk/GrVkVulkan.h" 15 16 #include "Test.h" 17 18 #include "GrBackendSurface.h" 19 #include "GrContextPriv.h" 20 #include "GrTextureProxy.h" 21 #include "GrTexture.h" 22 #include "SkImage.h" 23 #include "SkImage_Base.h" 24 #include "vk/GrVkGpu.h" 25 #include "vk/GrVkImageLayout.h" 26 #include "vk/GrVkTexture.h" 27 #include "vk/GrVkTypes.h" 28 29 DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkImageLayoutTest, reporter, ctxInfo) { 30 GrContext* context = ctxInfo.grContext(); 31 GrVkGpu* gpu = static_cast<GrVkGpu*>(context->priv().getGpu()); 32 33 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(nullptr, 1, 1, 34 GrColorType::kRGBA_8888, 35 false, 36 GrMipMapped::kNo); 37 REPORTER_ASSERT(reporter, backendTex.isValid()); 38 39 GrVkImageInfo info; 40 REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info)); 41 VkImageLayout initLayout = info.fImageLayout; 42 43 // Verify that setting that layout via a copy of a backendTexture is reflected in all the 44 // backendTextures. 45 GrBackendTexture backendTexCopy = backendTex; 46 REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info)); 47 REPORTER_ASSERT(reporter, initLayout == info.fImageLayout); 48 49 backendTexCopy.setVkImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 50 51 REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info)); 52 REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout); 53 54 REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info)); 55 REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout); 56 57 // Setting back the layout since we didn't actually change it 58 backendTex.setVkImageLayout(initLayout); 59 60 sk_sp<SkImage> wrappedImage = SkImage::MakeFromTexture(context, backendTex, 61 kTopLeft_GrSurfaceOrigin, 62 kRGBA_8888_SkColorType, 63 kPremul_SkAlphaType, nullptr); 64 REPORTER_ASSERT(reporter, wrappedImage.get()); 65 66 sk_sp<GrTextureProxy> texProxy = as_IB(wrappedImage)->asTextureProxyRef(context); 67 REPORTER_ASSERT(reporter, texProxy.get()); 68 REPORTER_ASSERT(reporter, texProxy->isInstantiated()); 69 GrTexture* texture = texProxy->peekTexture(); 70 REPORTER_ASSERT(reporter, texture); 71 72 // Verify that modifying the layout via the GrVkTexture is reflected in the GrBackendTexture 73 GrVkTexture* vkTexture = static_cast<GrVkTexture*>(texture); 74 REPORTER_ASSERT(reporter, initLayout == vkTexture->currentLayout()); 75 vkTexture->updateImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 76 77 REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info)); 78 REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == info.fImageLayout); 79 80 GrBackendTexture backendTexImage = wrappedImage->getBackendTexture(false); 81 REPORTER_ASSERT(reporter, backendTexImage.getVkImageInfo(&info)); 82 REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == info.fImageLayout); 83 84 // Verify that modifying the layout via the GrBackendTexutre is reflected in the GrVkTexture 85 backendTexImage.setVkImageLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 86 REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == vkTexture->currentLayout()); 87 88 vkTexture->updateImageLayout(initLayout); 89 90 REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info)); 91 REPORTER_ASSERT(reporter, initLayout == info.fImageLayout); 92 93 REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info)); 94 REPORTER_ASSERT(reporter, initLayout == info.fImageLayout); 95 96 REPORTER_ASSERT(reporter, backendTexImage.getVkImageInfo(&info)); 97 REPORTER_ASSERT(reporter, initLayout == info.fImageLayout); 98 99 // Check that we can do things like assigning the backend texture to invalid one, assign an 100 // invalid one, assin a backend texture to inself etc. Success here is that we don't hit any of 101 // our ref counting asserts. 102 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(backendTex, backendTexCopy)); 103 104 GrBackendTexture invalidTexture; 105 REPORTER_ASSERT(reporter, !invalidTexture.isValid()); 106 REPORTER_ASSERT(reporter, !GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTexCopy)); 107 108 backendTexCopy = invalidTexture; 109 REPORTER_ASSERT(reporter, !backendTexCopy.isValid()); 110 REPORTER_ASSERT(reporter, !GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTexCopy)); 111 112 invalidTexture = backendTex; 113 REPORTER_ASSERT(reporter, invalidTexture.isValid()); 114 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTex)); 115 116 invalidTexture = static_cast<decltype(invalidTexture)&>(invalidTexture); 117 REPORTER_ASSERT(reporter, invalidTexture.isValid()); 118 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(invalidTexture, invalidTexture)); 119 120 gpu->deleteTestingOnlyBackendTexture(backendTex); 121 } 122 123 static void testing_release_proc(void* ctx) { 124 int* count = (int*)ctx; 125 *count += 1; 126 } 127 128 // Test to make sure we don't call our release proc on an image until we've transferred it back to 129 // its original queue family. 130 DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkReleaseExternalQueueTest, reporter, ctxInfo) { 131 GrContext* context = ctxInfo.grContext(); 132 GrVkGpu* gpu = static_cast<GrVkGpu*>(context->priv().getGpu()); 133 if (!gpu->vkCaps().supportsExternalMemory()) { 134 return; 135 } 136 137 for (bool useExternal : {false, true}) { 138 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(nullptr, 1, 1, 139 GrColorType::kRGBA_8888, 140 false, 141 GrMipMapped::kNo); 142 sk_sp<SkImage> image; 143 int count = 0; 144 if (useExternal) { 145 // Make a backend texture with an external queue family; 146 GrVkImageInfo vkInfo; 147 if (!backendTex.getVkImageInfo(&vkInfo)) { 148 return; 149 } 150 vkInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL; 151 152 GrBackendTexture vkExtTex(1, 1, vkInfo); 153 REPORTER_ASSERT(reporter, vkExtTex.isValid()); 154 image = SkImage::MakeFromTexture(context, vkExtTex, 155 kTopLeft_GrSurfaceOrigin, 156 kRGBA_8888_SkColorType, 157 kPremul_SkAlphaType, 158 nullptr, testing_release_proc, 159 (void*)&count); 160 161 } else { 162 image = SkImage::MakeFromTexture(context, backendTex, 163 kTopLeft_GrSurfaceOrigin, 164 kRGBA_8888_SkColorType, 165 kPremul_SkAlphaType, 166 nullptr, testing_release_proc, 167 (void*)&count); 168 } 169 170 if (!image) { 171 continue; 172 } 173 174 REPORTER_ASSERT(reporter, !count); 175 176 GrTexture* texture = image->getTexture(); 177 REPORTER_ASSERT(reporter, texture); 178 GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture); 179 180 if (useExternal) { 181 // Testing helper so we claim that we don't need to transition from our fake external 182 // queue first. 183 vkTex->setCurrentQueueFamilyToGraphicsQueue(gpu); 184 } 185 186 image.reset(); 187 188 // Resetting the image should only trigger the release proc if we are not using an external 189 // queue. When using an external queue when we free the SkImage and the underlying 190 // GrTexture, we submit a queue transition on the command buffer. 191 if (useExternal) { 192 REPORTER_ASSERT(reporter, !count); 193 } else { 194 REPORTER_ASSERT(reporter, count == 1); 195 } 196 197 gpu->testingOnly_flushGpuAndSync(); 198 199 // Now that we flushed and waited the release proc should have be triggered. 200 REPORTER_ASSERT(reporter, count == 1); 201 202 gpu->deleteTestingOnlyBackendTexture(backendTex); 203 } 204 } 205 206 #endif 207