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