1 /*------------------------------------------------------------------------
2  * ------------------------
3  *
4  * Copyright (c) 2021 Google LLC.
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Sample cube faces that has been rendered to tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "deUniquePtr.hpp"
25 #include "deStringUtil.hpp"
26 
27 #include "tcuVectorType.hpp"
28 #include "tcuTextureUtil.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuTexture.hpp"
31 
32 #include "vkDefs.hpp"
33 #include "vkRef.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkTypeUtil.hpp"
42 #include "vkImageWithMemory.hpp"
43 #include "vkBarrierUtil.hpp"
44 
45 #include "vktTestCaseUtil.hpp"
46 #include "tcuTestLog.hpp"
47 
48 #include <string>
49 
50 using namespace vk;
51 
52 namespace vkt
53 {
54 namespace image
55 {
56 namespace
57 {
58 
59 using de::MovePtr;
60 using std::vector;
61 using tcu::ConstPixelBufferAccess;
62 using tcu::IVec2;
63 using tcu::IVec3;
64 using tcu::IVec4;
65 using tcu::PixelBufferAccess;
66 using tcu::TestLog;
67 using tcu::TextureLevel;
68 using tcu::Vec2;
69 using tcu::Vec4;
70 
makeImageCreateInfo(const IVec3 & size,const VkFormat & format,bool cubemap)71 inline VkImageCreateInfo makeImageCreateInfo(const IVec3 &size, const VkFormat &format, bool cubemap)
72 {
73     const VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
74                                     VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
75                                     VK_IMAGE_USAGE_SAMPLED_BIT;
76     const VkImageCreateFlags flags      = cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
77     const VkImageCreateInfo imageParams = {
78         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,  //  VkStructureType         sType;
79         DE_NULL,                              //  const void*             pNext;
80         flags,                                //  VkImageCreateFlags      flags;
81         VK_IMAGE_TYPE_2D,                     //  VkImageType             imageType;
82         format,                               //  VkFormat                format;
83         makeExtent3D(size.x(), size.y(), 1u), //  VkExtent3D              extent;
84         1u,                                   //  uint32_t                mipLevels;
85         (cubemap ? 6u : 1u),                  //  uint32_t                arrayLayers;
86         VK_SAMPLE_COUNT_1_BIT,                //  VkSampleCountFlagBits   samples;
87         VK_IMAGE_TILING_OPTIMAL,              //  VkImageTiling           tiling;
88         usage,                                //  VkImageUsageFlags       usage;
89         VK_SHARING_MODE_EXCLUSIVE,            //  VkSharingMode           sharingMode;
90         0u,                                   //  uint32_t                queueFamilyIndexCount;
91         DE_NULL,                              //  const uint32_t*         pQueueFamilyIndices;
92         VK_IMAGE_LAYOUT_UNDEFINED,            //  VkImageLayout           initialLayout;
93     };
94 
95     return imageParams;
96 }
97 
makeVertexBuffer(const DeviceInterface & vk,const VkDevice device,const uint32_t queueFamilyIndex)98 Move<VkBuffer> makeVertexBuffer(const DeviceInterface &vk, const VkDevice device, const uint32_t queueFamilyIndex)
99 {
100     const VkBufferCreateInfo vertexBufferParams = {
101         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType      sType;
102         DE_NULL,                              // const void*          pNext;
103         0u,                                   // VkBufferCreateFlags  flags;
104         1024u,                                // VkDeviceSize     size;
105         VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags   usage;
106         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode        sharingMode;
107         1u,                                   // uint32_t             queueFamilyIndexCount;
108         &queueFamilyIndex                     // const uint32_t*      pQueueFamilyIndices;
109     };
110 
111     Move<VkBuffer> vertexBuffer = createBuffer(vk, device, &vertexBufferParams);
112     ;
113     return vertexBuffer;
114 }
115 
116 class SampleDrawnCubeFaceTestInstance : public TestInstance
117 {
118 public:
119     SampleDrawnCubeFaceTestInstance(Context &context, const IVec2 &size, const VkFormat format);
120     tcu::TestStatus iterate(void);
121 
122 private:
123     const tcu::IVec2 &m_size;
124     const VkFormat m_format;
125 };
126 
SampleDrawnCubeFaceTestInstance(Context & context,const IVec2 & size,const VkFormat format)127 SampleDrawnCubeFaceTestInstance::SampleDrawnCubeFaceTestInstance(Context &context, const IVec2 &size,
128                                                                  const VkFormat format)
129     : TestInstance(context)
130     , m_size(size)
131     , m_format(format)
132 {
133 }
134 
135 template <typename T>
sizeInBytes(const vector<T> & vec)136 inline size_t sizeInBytes(const vector<T> &vec)
137 {
138     return vec.size() * sizeof(vec[0]);
139 }
140 
makeSampler(const DeviceInterface & vk,const VkDevice & device)141 Move<VkSampler> makeSampler(const DeviceInterface &vk, const VkDevice &device)
142 {
143     const VkSamplerCreateInfo samplerParams = {
144         VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,   // VkStructureType          sType;
145         DE_NULL,                                 // const void*              pNext;
146         (VkSamplerCreateFlags)0,                 // VkSamplerCreateFlags     flags;
147         VK_FILTER_LINEAR,                        // VkFilter                 magFilter;
148         VK_FILTER_LINEAR,                        // VkFilter                 minFilter;
149         VK_SAMPLER_MIPMAP_MODE_NEAREST,          // VkSamplerMipmapMode      mipmapMode;
150         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode     addressModeU;
151         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode     addressModeV;
152         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode     addressModeW;
153         0.0f,                                    // float                    mipLodBias;
154         VK_FALSE,                                // VkBool32                 anisotropyEnable;
155         1.0f,                                    // float                    maxAnisotropy;
156         VK_FALSE,                                // VkBool32                 compareEnable;
157         VK_COMPARE_OP_ALWAYS,                    // VkCompareOp              compareOp;
158         0.0f,                                    // float                    minLod;
159         0.0f,                                    // float                    maxLod;
160         VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor            borderColor;
161         VK_FALSE,                                // VkBool32                 unnormalizedCoordinates;
162     };
163 
164     return createSampler(vk, device, &samplerParams);
165 }
166 
167 // Draw a quad covering the whole framebuffer
genFullQuadVertices(void)168 vector<Vec4> genFullQuadVertices(void)
169 {
170     vector<Vec4> vertices;
171     vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
172     vertices.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
173     vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
174     vertices.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
175     vertices.push_back(Vec4(1.0f, 1.0f, 0.0f, 1.0f));
176     vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
177 
178     return vertices;
179 }
180 
181 struct Vertex
182 {
Vertexvkt::image::__anonbbe02f7e0111::Vertex183     Vertex(Vec4 vertices_, Vec2 uv_) : vertices(vertices_), uv(uv_)
184     {
185     }
186     Vec4 vertices;
187     Vec2 uv;
188 
189     static VkVertexInputBindingDescription getBindingDescription(void);
190     static vector<VkVertexInputAttributeDescription> getAttributeDescriptions(void);
191 };
192 
getBindingDescription(void)193 VkVertexInputBindingDescription Vertex::getBindingDescription(void)
194 {
195     static const VkVertexInputBindingDescription desc = {
196         0u,                                    // uint32_t             binding;
197         static_cast<uint32_t>(sizeof(Vertex)), // uint32_t             stride;
198         VK_VERTEX_INPUT_RATE_VERTEX,           // VkVertexInputRate    inputRate;
199     };
200 
201     return desc;
202 }
203 
getAttributeDescriptions(void)204 vector<VkVertexInputAttributeDescription> Vertex::getAttributeDescriptions(void)
205 {
206     static const vector<VkVertexInputAttributeDescription> desc = {
207         {
208             0u,                                                // uint32_t    location;
209             0u,                                                // uint32_t    binding;
210             vk::VK_FORMAT_R32G32B32A32_SFLOAT,                 // VkFormat    format;
211             static_cast<uint32_t>(offsetof(Vertex, vertices)), // uint32_t    offset;
212         },
213         {
214             1u,                                          // uint32_t    location;
215             0u,                                          // uint32_t    binding;
216             vk::VK_FORMAT_R32G32_SFLOAT,                 // VkFormat    format;
217             static_cast<uint32_t>(offsetof(Vertex, uv)), // uint32_t    offset;
218         },
219     };
220 
221     return desc;
222 }
223 
genTextureCoordinates(void)224 vector<Vertex> genTextureCoordinates(void)
225 {
226     vector<Vertex> vertices;
227     vertices.push_back(Vertex(Vec4(-1.0f, -1.0f, 0.0f, 1.0f), Vec2(0.0f, 0.0f)));
228     vertices.push_back(Vertex(Vec4(1.0f, -1.0f, 0.0f, 1.0f), Vec2(1.0f, 0.0f)));
229     vertices.push_back(Vertex(Vec4(-1.0f, 1.0f, 0.0f, 1.0f), Vec2(0.0f, 1.0f)));
230     vertices.push_back(Vertex(Vec4(1.0f, -1.0f, 0.0f, 1.0f), Vec2(1.0f, 0.0f)));
231     vertices.push_back(Vertex(Vec4(1.0f, 1.0f, 0.0f, 1.0f), Vec2(1.0f, 1.0f)));
232     vertices.push_back(Vertex(Vec4(-1.0f, 1.0f, 0.0f, 1.0f), Vec2(0.0f, 1.0f)));
233 
234     return vertices;
235 }
236 
iterate(void)237 tcu::TestStatus SampleDrawnCubeFaceTestInstance::iterate(void)
238 {
239     DE_ASSERT(m_format == VK_FORMAT_R8G8B8A8_UNORM);
240 
241     const DeviceInterface &vk       = m_context.getDeviceInterface();
242     const VkDevice device           = m_context.getDevice();
243     Allocator &allocator            = m_context.getDefaultAllocator();
244     const VkQueue queue             = m_context.getUniversalQueue();
245     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
246     const VkDeviceSize bufferSize   = 1024;
247 
248     const uint32_t layerStart = 0;
249     const uint32_t layerCount = 6;
250     const uint32_t levelCount = 1;
251 
252     const IVec3 imageSize       = {m_size.x(), m_size.y(), (int32_t)layerCount};
253     const VkExtent2D renderSize = {uint32_t(m_size.x()), uint32_t(m_size.y())};
254     const VkRect2D renderArea   = makeRect2D(makeExtent3D(m_size.x(), m_size.y(), 1u));
255     const vector<VkRect2D> scissors(1u, renderArea);
256     const vector<VkViewport> viewports(1u, makeViewport(makeExtent3D(m_size.x(), m_size.y(), 1u)));
257 
258     const vector<Vec4> vertices = genFullQuadVertices();
259     Move<VkBuffer> vertexBuffer = makeVertexBuffer(vk, device, queueFamilyIndex);
260     MovePtr<Allocation> vertexBufferAlloc =
261         bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
262     const VkDeviceSize vertexBufferOffset = 0ull;
263 
264     deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], sizeInBytes(vertices));
265     flushAlloc(vk, device, *vertexBufferAlloc);
266 
267     // Create a cubemap image.
268     const VkImageCreateInfo cubemapCreateInfo = makeImageCreateInfo(imageSize, m_format, true);
269     const VkImageSubresourceRange cubemapSubresourceRange =
270         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, levelCount, layerStart, layerCount);
271     const ImageWithMemory cubemapImage(vk, device, m_context.getDefaultAllocator(), cubemapCreateInfo,
272                                        MemoryRequirement::Any);
273     Move<VkImageView> cubemapImageView =
274         makeImageView(vk, device, *cubemapImage, VK_IMAGE_VIEW_TYPE_CUBE, m_format, cubemapSubresourceRange);
275 
276     // Create a sampler for the cubemap and bind it.
277     Move<VkImageView> sampledImageView =
278         makeImageView(vk, device, *cubemapImage, VK_IMAGE_VIEW_TYPE_CUBE, m_format, cubemapSubresourceRange);
279     const Unique<VkSampler> cubemapSampler(makeSampler(vk, device));
280     const VkDescriptorImageInfo descriptorImageInfo =
281         makeDescriptorImageInfo(cubemapSampler.get(), *sampledImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
282 
283     const auto descriptorSetLayout(DescriptorSetLayoutBuilder()
284                                        .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
285                                                                 VK_SHADER_STAGE_FRAGMENT_BIT, &cubemapSampler.get())
286                                        .build(vk, device));
287 
288     const Unique<VkDescriptorPool> descriptorPool(
289         DescriptorPoolBuilder()
290             .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u)
291             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
292 
293     const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
294 
295     DescriptorSetUpdateBuilder()
296         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
297                      VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descriptorImageInfo)
298         .update(vk, device);
299 
300     // Generate texture coordinates for the sampler.
301     vector<Vertex> uvCoordinates = genTextureCoordinates();
302     Move<VkBuffer> uvBuffer      = makeVertexBuffer(vk, device, queueFamilyIndex);
303     de::MovePtr<Allocation> uvBufferAlloc =
304         bindBuffer(vk, device, allocator, *uvBuffer, MemoryRequirement::HostVisible);
305     const VkDeviceSize uvBufferOffset = 0ull;
306 
307     deMemcpy(uvBufferAlloc->getHostPtr(), &uvCoordinates[0], uvCoordinates.size() * sizeof(Vertex));
308     flushAlloc(vk, device, *uvBufferAlloc);
309 
310     // Sampled values will be written to this image.
311     const VkImageSubresourceRange targetSubresourceRange =
312         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, levelCount, layerStart, 1);
313     const VkImageCreateInfo targetImageCreateInfo = makeImageCreateInfo(imageSize, m_format, false);
314     const ImageWithMemory targetImage(vk, device, m_context.getDefaultAllocator(), targetImageCreateInfo,
315                                       MemoryRequirement::Any);
316     Move<VkImageView> targetImageView =
317         makeImageView(vk, device, *targetImage, VK_IMAGE_VIEW_TYPE_2D, m_format, targetSubresourceRange);
318 
319     // We use a push constant to hold count for how many times the shader has written to the cubemap.
320     const VkPushConstantRange pushConstantRange = {
321         VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags    stageFlags;
322         0u,                           // uint32_t              offset;
323         (uint32_t)sizeof(uint32_t),   // uint32_t              size;
324     };
325 
326     const Move<VkCommandPool> cmdPool =
327         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
328     const Move<VkCommandBuffer> cmdBuffer =
329         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
330 
331     // Create two graphic pipelines. One for writing to the cubemap and the other for sampling it.
332     Move<VkRenderPass> renderPass1 = makeRenderPass(
333         vk, device, m_format, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
334         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
335         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, DE_NULL);
336 
337     Move<VkFramebuffer> framebuffer1 =
338         makeFramebuffer(vk, device, *renderPass1, cubemapImageView.get(), renderSize.width, renderSize.height);
339 
340     const Move<VkShaderModule> vertexModule1 =
341         createShaderModule(vk, device, m_context.getBinaryCollection().get("vert1"), 0u);
342     const Move<VkShaderModule> fragmentModule1 =
343         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag1"), 0u);
344 
345     const Move<VkPipelineLayout> pipelineLayout1 = makePipelineLayout(vk, device, 0, DE_NULL, 1, &pushConstantRange);
346     const Move<VkPipeline> graphicsPipeline1     = makeGraphicsPipeline(
347         vk, device, pipelineLayout1.get(), vertexModule1.get(), DE_NULL, DE_NULL, DE_NULL, fragmentModule1.get(),
348         renderPass1.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, DE_NULL);
349 
350     Move<VkRenderPass> renderPass2 = makeRenderPass(vk, device, m_format, VK_FORMAT_UNDEFINED,
351                                                     VK_ATTACHMENT_LOAD_OP_LOAD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
352 
353     Move<VkFramebuffer> framebuffer2 =
354         makeFramebuffer(vk, device, *renderPass2, targetImageView.get(), renderSize.width, renderSize.height);
355 
356     Move<VkShaderModule> vertexModule2 =
357         createShaderModule(vk, device, m_context.getBinaryCollection().get("vert2"), 0u);
358     Move<VkShaderModule> fragmentModule2 =
359         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag2"), 0u);
360 
361     const Move<VkPipelineLayout> pipelineLayout2 = makePipelineLayout(vk, device, *descriptorSetLayout);
362 
363     const auto vtxBindingDescription = Vertex::getBindingDescription();
364     const auto vtxAttrDescriptions   = Vertex::getAttributeDescriptions();
365 
366     const VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
367         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType
368         nullptr,                                                   // const void*                                 pNext
369         0u,                                                        // VkPipelineVertexInputStateCreateFlags       flags
370         1u,                     // uint32_t                                    vertexBindingDescriptionCount
371         &vtxBindingDescription, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions
372         static_cast<uint32_t>(
373             vtxAttrDescriptions.size()), // uint32_t                                    vertexAttributeDescriptionCount
374         vtxAttrDescriptions.data(),      // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
375     };
376 
377     const Move<VkPipeline> graphicsPipeline2 = makeGraphicsPipeline(
378         vk, device, pipelineLayout2.get(), vertexModule2.get(), DE_NULL, DE_NULL, DE_NULL, fragmentModule2.get(),
379         renderPass2.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, &vertexInputInfo);
380 
381     // The values sampled in the second pipeline will be copied to this buffer.
382     const VkBufferCreateInfo resultBufferCreateInfo =
383         makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
384     Move<VkBuffer> resultBuffer = createBuffer(vk, device, &resultBufferCreateInfo);
385     MovePtr<Allocation> resultBufferMemory =
386         allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);
387     MovePtr<TextureLevel> resultImage(new TextureLevel(mapVkFormat(m_format), renderSize.width, renderSize.height, 1));
388 
389     VK_CHECK(
390         vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));
391 
392     // Clear the cubemap faces and the target image as black.
393     const Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
394 
395     clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(),
396                     cubemapImage.get(), clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
397                     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, layerCount);
398 
399     clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(),
400                     targetImage.get(), clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
401                     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 1u);
402 
403     // Run the shaders twice.
404     beginCommandBuffer(vk, *cmdBuffer);
405 
406     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout2, 0u, 1u,
407                              &descriptorSet.get(), 0u, DE_NULL);
408 
409     for (int pass = 0; pass < 2; pass++)
410     {
411         //  Draw on the first cube map face.
412         vk.cmdPushConstants(*cmdBuffer, *pipelineLayout1, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(int32_t), &pass);
413         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline1);
414         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
415 
416         beginRenderPass(vk, *cmdBuffer, *renderPass1, *framebuffer1, makeRect2D(0, 0, imageSize.x(), imageSize.y()), 0,
417                         DE_NULL);
418         vk.cmdDraw(*cmdBuffer, static_cast<uint32_t>(vertices.size()), 1u, 0u, 0u);
419         endRenderPass(vk, *cmdBuffer);
420 
421         {
422             const auto barrier = makeImageMemoryBarrier(
423                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
424                 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, cubemapImage.get(),
425                 cubemapSubresourceRange);
426             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
427                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier);
428         }
429 
430         // Sample the four faces around the first face.
431         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline2);
432 
433         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &uvBuffer.get(), &uvBufferOffset);
434 
435         beginRenderPass(vk, *cmdBuffer, *renderPass2, *framebuffer2, makeRect2D(0, 0, imageSize.x(), imageSize.y()), 0u,
436                         DE_NULL);
437         vk.cmdDraw(*cmdBuffer, 6u, 1u, 0u, 0u);
438         endRenderPass(vk, *cmdBuffer);
439 
440         if (pass == 0)
441         {
442             const auto barrier = makeImageMemoryBarrier(
443                 0u, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
444                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, cubemapImage.get(), cubemapSubresourceRange);
445             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
446                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier);
447 
448             const auto barrier2 = makeImageMemoryBarrier(
449                 0u, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
450                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, targetImage.get(), targetSubresourceRange);
451             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
452                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier2);
453         }
454     }
455 
456     // Read the result buffer data
457     copyImageToBuffer(vk, *cmdBuffer, *targetImage, *resultBuffer, IVec2(m_size.x(), m_size.y()),
458                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
459 
460     endCommandBuffer(vk, *cmdBuffer);
461     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
462 
463     invalidateAlloc(vk, device, *resultBufferMemory);
464 
465     tcu::clear(resultImage->getAccess(), IVec4(0));
466     tcu::copy(resultImage->getAccess(),
467               ConstPixelBufferAccess(resultImage.get()->getFormat(), resultImage.get()->getSize(),
468                                      resultBufferMemory->getHostPtr()));
469 
470     bool result = true;
471 
472     // The first run writes pure red and the second pure blue hence the value of the red component
473     // should be 0.0 and the value in the blue channel > 0.0.
474     for (uint32_t y = 0; y < renderSize.height; y++)
475     {
476         const uint8_t *ptr =
477             static_cast<const uint8_t *>(resultImage->getAccess().getPixelPtr(renderSize.width - 1, y, 0));
478         const IVec4 val = IVec4(ptr[0], ptr[1], ptr[2], ptr[3]);
479         if (!(val[0] == 0 && val[1] > 0))
480             result = false;
481     }
482 
483     // Log attachment contents
484     m_context.getTestContext().getLog() << tcu::TestLog::ImageSet("Attachment ", "")
485                                         << tcu::TestLog::Image("Rendered image", "Rendered image",
486                                                                resultImage->getAccess())
487                                         << tcu::TestLog::EndImageSet;
488 
489     if (result)
490         return tcu::TestStatus::pass("pass");
491     else
492         return tcu::TestStatus::fail("fail");
493 }
494 
495 class SampleDrawnCubeFaceTest : public TestCase
496 {
497 public:
498     SampleDrawnCubeFaceTest(tcu::TestContext &testCtx, const std::string &name, const tcu::IVec2 &size,
499                             const VkFormat format);
500 
501     void initPrograms(SourceCollections &programCollection) const;
502     TestInstance *createInstance(Context &context) const;
503 
504 private:
505     const tcu::IVec2 m_size;
506     const VkFormat m_format;
507 };
508 
SampleDrawnCubeFaceTest(tcu::TestContext & testCtx,const std::string & name,const tcu::IVec2 & size,const VkFormat format)509 SampleDrawnCubeFaceTest::SampleDrawnCubeFaceTest(tcu::TestContext &testCtx, const std::string &name,
510                                                  const tcu::IVec2 &size, const VkFormat format)
511     : TestCase(testCtx, name)
512     , m_size(size)
513     , m_format(format)
514 {
515 }
516 
initPrograms(SourceCollections & programCollection) const517 void SampleDrawnCubeFaceTest::initPrograms(SourceCollections &programCollection) const
518 {
519     std::ostringstream pipeline1VertexSrc;
520     pipeline1VertexSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
521                        << "layout(location = 0) in vec4 a_position;\n"
522                        << "void main (void) {\n"
523                        << "    gl_Position = a_position;\n"
524                        << "}\n";
525 
526     std::ostringstream pipeline1FragmentSrc;
527     pipeline1FragmentSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
528                          << "layout(location = 0) out vec4 outColor;\n"
529                          << "layout(push_constant) uniform constants {\n"
530                          << "     int pass;\n"
531                          << "} pc;\n"
532                          << "void main() {\n"
533                          << "   if (pc.pass == 1) {\n"
534                          << "      outColor = vec4(0., 1., 1., 1.);\n"
535                          << "    } else {\n"
536                          << "      outColor = vec4(1., 0., 1., 1.);\n"
537                          << "    }\n"
538                          << "}\n";
539 
540     std::ostringstream pipeline2VertexSrc;
541     pipeline2VertexSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
542                        << "layout(location = 0) in highp vec4 a_position;\n"
543                        << "layout(location = 1) in vec2 inTexCoord;\n"
544                        << "layout(location = 1) out vec2 fragTexCoord;\n"
545                        << "void main (void) {\n"
546                        << "    gl_Position = a_position;\n"
547                        << "    fragTexCoord = inTexCoord;\n"
548                        << "}\n";
549 
550     std::ostringstream pipeline2FragmentSrc;
551     pipeline2FragmentSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
552                          << "layout(location = 0) out vec4 outColor;\n"
553                          << "layout(location = 1) in vec2 fragTexCoord;\n"
554                          << "layout(binding = 0) uniform samplerCube texSampler;\n"
555                          << "void main() {\n"
556                          << "     outColor = texture(texSampler, vec3(fragTexCoord.x, 1.0, fragTexCoord.y));\n"
557                          << "     outColor += texture(texSampler, vec3(fragTexCoord.x, -1.0, fragTexCoord.y));\n"
558                          << "     outColor += texture(texSampler, vec3(fragTexCoord.x, fragTexCoord.y, 1.0));\n"
559                          << "     outColor += texture(texSampler, vec3(fragTexCoord.x, fragTexCoord.y, -1.0));\n"
560                          << "     outColor /= 4.;\n"
561                          << "}\n";
562 
563     programCollection.glslSources.add("vert1") << glu::VertexSource(pipeline1VertexSrc.str());
564     programCollection.glslSources.add("vert2") << glu::VertexSource(pipeline2VertexSrc.str());
565     programCollection.glslSources.add("frag1") << glu::FragmentSource(pipeline1FragmentSrc.str());
566     programCollection.glslSources.add("frag2") << glu::FragmentSource(pipeline2FragmentSrc.str());
567 }
568 
createInstance(Context & context) const569 TestInstance *SampleDrawnCubeFaceTest::createInstance(Context &context) const
570 {
571     return new SampleDrawnCubeFaceTestInstance(context, m_size, m_format);
572 }
573 
574 } // namespace
575 
createImageSampleDrawnCubeFaceTests(tcu::TestContext & testCtx)576 tcu::TestCaseGroup *createImageSampleDrawnCubeFaceTests(tcu::TestContext &testCtx)
577 {
578     const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
579     const tcu::IVec2 size = tcu::IVec2(8, 8);
580 
581     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "sample_cubemap"));
582 
583     testGroup->addChild(new SampleDrawnCubeFaceTest(testCtx, "write_face_0", size, format));
584 
585     return testGroup.release();
586 }
587 
588 } // namespace image
589 } // namespace vkt
590