1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Intel Corporation
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Image Object Util
23 *//*--------------------------------------------------------------------*/
24
25#include "vktDrawImageObjectUtil.hpp"
26
27#include "tcuSurface.hpp"
28#include "tcuVectorUtil.hpp"
29
30#include "vkRefUtil.hpp"
31#include "vkQueryUtil.hpp"
32#include "vkImageUtil.hpp"
33#include "vktDrawCreateInfoUtil.hpp"
34#include "vktDrawBufferObjectUtil.hpp"
35
36#include "tcuTextureUtil.hpp"
37
38namespace vkt
39{
40namespace Draw
41{
42
43void MemoryOp::pack (int				pixelSize,
44					 int				width,
45					 int				height,
46					 int				depth,
47					 vk::VkDeviceSize	rowPitchOrZero,
48					 vk::VkDeviceSize	depthPitchOrZero,
49					 const void *		srcBuffer,
50					 void *				destBuffer)
51{
52	vk::VkDeviceSize rowPitch	= rowPitchOrZero;
53	vk::VkDeviceSize depthPitch	= depthPitchOrZero;
54
55	if (rowPitch == 0)
56		rowPitch = width * pixelSize;
57
58	if (depthPitch == 0)
59		depthPitch = rowPitch * height;
60
61	const vk::VkDeviceSize size = depthPitch * depth;
62
63	const deUint8 *srcRow = reinterpret_cast<const deUint8 *>(srcBuffer);
64	const deUint8 *srcStart;
65	srcStart = srcRow;
66	deUint8 *dstRow = reinterpret_cast<deUint8 *>(destBuffer);
67	deUint8 *dstStart;
68	dstStart = dstRow;
69
70	if (rowPitch == static_cast<vk::VkDeviceSize>(width * pixelSize) &&
71		depthPitch == static_cast<vk::VkDeviceSize>(rowPitch * height))
72	{
73		// fast path
74		deMemcpy(dstRow, srcRow, static_cast<size_t>(size));
75	}
76	else
77	{
78		// slower, per row path
79		for (int d = 0; d < depth; d++)
80		{
81			vk::VkDeviceSize offsetDepthDst = d * depthPitch;
82			vk::VkDeviceSize offsetDepthSrc = d * (pixelSize * width * height);
83			srcRow = srcStart + offsetDepthSrc;
84			dstRow = dstStart + offsetDepthDst;
85			for (int r = 0; r < height; ++r)
86			{
87				deMemcpy(dstRow, srcRow, static_cast<size_t>(rowPitch));
88				srcRow += pixelSize * width;
89				dstRow += rowPitch;
90			}
91		}
92	}
93}
94
95void MemoryOp::unpack (int					pixelSize,
96					   int					width,
97					   int					height,
98					   int					depth,
99					   vk::VkDeviceSize		rowPitchOrZero,
100					   vk::VkDeviceSize		depthPitchOrZero,
101					   const void *			srcBuffer,
102					   void *				destBuffer)
103{
104	vk::VkDeviceSize rowPitch	= rowPitchOrZero;
105	vk::VkDeviceSize depthPitch = depthPitchOrZero;
106
107	if (rowPitch == 0)
108		rowPitch = width * pixelSize;
109
110	if (depthPitch == 0)
111		depthPitch = rowPitch * height;
112
113	const vk::VkDeviceSize size = depthPitch * depth;
114
115	const deUint8 *srcRow = reinterpret_cast<const deUint8 *>(srcBuffer);
116	const deUint8 *srcStart;
117	srcStart = srcRow;
118	deUint8 *dstRow = reinterpret_cast<deUint8 *>(destBuffer);
119	deUint8 *dstStart;
120	dstStart = dstRow;
121
122	if (rowPitch == static_cast<vk::VkDeviceSize>(width * pixelSize) &&
123		depthPitch == static_cast<vk::VkDeviceSize>(rowPitch * height))
124	{
125		// fast path
126		deMemcpy(dstRow, srcRow, static_cast<size_t>(size));
127	}
128	else {
129		// slower, per row path
130		for (size_t d = 0; d < (size_t)depth; d++)
131		{
132			vk::VkDeviceSize offsetDepthDst = d * (pixelSize * width * height);
133			vk::VkDeviceSize offsetDepthSrc = d * depthPitch;
134			srcRow = srcStart + offsetDepthSrc;
135			dstRow = dstStart + offsetDepthDst;
136			for (int r = 0; r < height; ++r)
137			{
138				deMemcpy(dstRow, srcRow, static_cast<size_t>(pixelSize * width));
139				srcRow += rowPitch;
140				dstRow += pixelSize * width;
141			}
142		}
143	}
144}
145
146Image::Image (const vk::DeviceInterface& vk,
147			  vk::VkDevice				device,
148			  vk::VkFormat				format,
149			  const vk::VkExtent3D&		extend,
150			  deUint32					levelCount,
151			  deUint32					layerCount,
152			  vk::Move<vk::VkImage>		object_)
153	: m_allocation		(DE_NULL)
154	, m_object			(object_)
155	, m_format			(format)
156	, m_extent			(extend)
157	, m_levelCount		(levelCount)
158	, m_layerCount		(layerCount)
159	, m_vk(vk)
160	, m_device(device)
161{
162}
163
164tcu::ConstPixelBufferAccess Image::readSurface (vk::VkQueue					queue,
165												vk::Allocator&				allocator,
166												vk::VkImageLayout			layout,
167												vk::VkOffset3D				offset,
168												int							width,
169												int							height,
170												vk::VkImageAspectFlagBits	aspect,
171												unsigned int				mipLevel,
172												unsigned int				arrayElement)
173{
174	m_pixelAccessData.resize(width * height * vk::mapVkFormat(m_format).getPixelSize());
175	deMemset(m_pixelAccessData.data(), 0, m_pixelAccessData.size());
176	if (aspect == vk::VK_IMAGE_ASPECT_COLOR_BIT)
177	{
178		read(queue, allocator, layout, offset, width, height, 1, mipLevel, arrayElement, aspect, vk::VK_IMAGE_TYPE_2D,
179		m_pixelAccessData.data());
180	}
181	if (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT || aspect == vk::VK_IMAGE_ASPECT_STENCIL_BIT)
182	{
183		readUsingBuffer(queue, allocator, layout, offset, width, height, 1, mipLevel, arrayElement, aspect, m_pixelAccessData.data());
184	}
185	return tcu::ConstPixelBufferAccess(vk::mapVkFormat(m_format), width, height, 1, m_pixelAccessData.data());
186}
187
188tcu::ConstPixelBufferAccess Image::readVolume (vk::VkQueue					queue,
189											   vk::Allocator&				allocator,
190											   vk::VkImageLayout			layout,
191											   vk::VkOffset3D				offset,
192											   int							width,
193											   int							height,
194											   int							depth,
195											   vk::VkImageAspectFlagBits	aspect,
196											   unsigned int					mipLevel,
197											   unsigned int					arrayElement)
198{
199	m_pixelAccessData.resize(width * height * depth * vk::mapVkFormat(m_format).getPixelSize());
200	deMemset(m_pixelAccessData.data(), 0, m_pixelAccessData.size());
201	if (aspect == vk::VK_IMAGE_ASPECT_COLOR_BIT)
202	{
203		read(queue, allocator, layout, offset, width, height, depth, mipLevel, arrayElement, aspect, vk::VK_IMAGE_TYPE_3D,
204		m_pixelAccessData.data());
205	}
206	if (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT || aspect == vk::VK_IMAGE_ASPECT_STENCIL_BIT)
207	{
208		readUsingBuffer(queue, allocator, layout, offset, width, height, depth, mipLevel, arrayElement, aspect, m_pixelAccessData.data());
209	}
210	return tcu::ConstPixelBufferAccess(vk::mapVkFormat(m_format), width, height, depth, m_pixelAccessData.data());
211}
212
213tcu::ConstPixelBufferAccess Image::readSurface1D(vk::VkQueue				queue,
214												 vk::Allocator&				allocator,
215												 vk::VkImageLayout			layout,
216												 vk::VkOffset3D				offset,
217												 int						width,
218												 vk::VkImageAspectFlagBits	aspect,
219												 unsigned int				mipLevel,
220												 unsigned int				arrayElement)
221{
222	m_pixelAccessData.resize(width * vk::mapVkFormat(m_format).getPixelSize());
223	deMemset(m_pixelAccessData.data(), 0, m_pixelAccessData.size());
224	if (aspect == vk::VK_IMAGE_ASPECT_COLOR_BIT)
225	{
226		read(queue, allocator, layout, offset, width, 1, 1, mipLevel, arrayElement, aspect, vk::VK_IMAGE_TYPE_1D,
227		m_pixelAccessData.data());
228	}
229	if (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT || aspect == vk::VK_IMAGE_ASPECT_STENCIL_BIT)
230	{
231		readUsingBuffer(queue, allocator, layout, offset, width, 1, 1, mipLevel, arrayElement, aspect,
232		m_pixelAccessData.data());
233	}
234	return tcu::ConstPixelBufferAccess(vk::mapVkFormat(m_format), width, 1, 1, m_pixelAccessData.data());
235}
236
237void Image::read (vk::VkQueue					queue,
238				  vk::Allocator&				allocator,
239				  vk::VkImageLayout				layout,
240				  vk::VkOffset3D				offset,
241				  int							width,
242				  int							height,
243				  int							depth,
244				  unsigned int					mipLevel,
245				  unsigned int					arrayElement,
246				  vk::VkImageAspectFlagBits		aspect,
247				  vk::VkImageType				type,
248				  void *						data)
249{
250	DE_ASSERT(layout == vk::VK_IMAGE_LAYOUT_GENERAL || layout == vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
251
252	de::SharedPtr<Image> stagingResource = copyToLinearImage(queue, allocator, layout, offset, width,
253															 height, depth, mipLevel, arrayElement, aspect, type);
254	const vk::VkOffset3D zeroOffset = {0, 0, 0};
255	stagingResource->readLinear(zeroOffset, width, height, depth, 0, 0, aspect, data);
256}
257
258void Image::readUsingBuffer (vk::VkQueue				queue,
259							 vk::Allocator&				allocator,
260							 vk::VkImageLayout			layout,
261							 vk::VkOffset3D				offset,
262							 int						width,
263							 int						height,
264							 int						depth,
265							 unsigned int				mipLevel,
266							 unsigned int				arrayElement,
267							 vk::VkImageAspectFlagBits	aspect,
268							 void *						data)
269{
270	DE_ASSERT(layout == vk::VK_IMAGE_LAYOUT_GENERAL || layout == vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);;
271
272	de::SharedPtr<Buffer> stagingResource;
273
274	bool isCombinedType = isCombinedDepthStencilType(vk::mapVkFormat(m_format).type);
275	vk::VkDeviceSize bufferSize = 0;
276
277	if (!isCombinedType)
278		bufferSize = vk::mapVkFormat(m_format).getPixelSize() * width * height * depth;
279
280	if (isCombinedType)
281	{
282		int pixelSize = 0;
283		switch (m_format)
284		{
285			case vk::VK_FORMAT_D16_UNORM_S8_UINT:
286				pixelSize = (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT) ? 2 : 1;
287				break;
288			case  vk::VK_FORMAT_D32_SFLOAT_S8_UINT:
289				pixelSize = (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT) ? 4 : 1;
290				break;
291			case vk::VK_FORMAT_X8_D24_UNORM_PACK32:
292			case vk::VK_FORMAT_D24_UNORM_S8_UINT:
293				pixelSize = (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT) ? 3 : 1;
294				break;
295
296			default:
297				DE_FATAL("Not implemented");
298		}
299		bufferSize = pixelSize*width*height*depth;
300	}
301
302	BufferCreateInfo stagingBufferResourceCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
303	stagingResource = Buffer::createAndAlloc(m_vk, m_device, stagingBufferResourceCreateInfo, allocator, vk::MemoryRequirement::HostVisible);
304
305	{
306		//todo [scygan] get proper queueFamilyIndex
307		CmdPoolCreateInfo copyCmdPoolCreateInfo(0);
308		vk::Unique<vk::VkCommandPool> copyCmdPool(vk::createCommandPool(m_vk, m_device, &copyCmdPoolCreateInfo));
309
310		const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
311		{
312			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
313			DE_NULL,											// const void*				pNext;
314			*copyCmdPool,										// VkCommandPool			commandPool;
315			vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
316			1u,													// deUint32					bufferCount;
317		};
318		vk::Unique<vk::VkCommandBuffer> copyCmdBuffer(vk::allocateCommandBuffer(m_vk, m_device, &cmdBufferAllocateInfo));
319
320		CmdBufferBeginInfo beginInfo;
321		VK_CHECK(m_vk.beginCommandBuffer(*copyCmdBuffer, &beginInfo));
322
323		if (layout == vk::VK_IMAGE_LAYOUT_UNDEFINED)
324		{
325			layout = vk::VK_IMAGE_LAYOUT_GENERAL;
326
327			vk::VkImageMemoryBarrier barrier;
328			barrier.sType = vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
329			barrier.pNext = DE_NULL;
330			barrier.srcAccessMask = 0;
331			barrier.dstAccessMask = 0;
332			barrier.oldLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
333			barrier.newLayout = vk::VK_IMAGE_LAYOUT_GENERAL;
334			barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
335			barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
336			barrier.image = object();
337
338			barrier.subresourceRange.aspectMask = aspect;
339			barrier.subresourceRange.baseMipLevel = 0;
340			barrier.subresourceRange.levelCount = m_levelCount;
341			barrier.subresourceRange.baseArrayLayer = 0;
342			barrier.subresourceRange.layerCount = m_layerCount;
343
344			m_vk.cmdPipelineBarrier(*copyCmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
345									0, (const vk::VkMemoryBarrier*)DE_NULL,
346									0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
347									1, &barrier);
348		}
349
350		vk::VkBufferImageCopy region =
351		{
352			0, 0, 0,
353			{ (vk::VkImageAspectFlags)aspect, mipLevel, arrayElement, 1 },
354			offset,
355			{ (deUint32)width, (deUint32)height, (deUint32)depth }
356		};
357
358		m_vk.cmdCopyImageToBuffer(*copyCmdBuffer, object(), layout, stagingResource->object(), 1, &region);
359		VK_CHECK(m_vk.endCommandBuffer(*copyCmdBuffer));
360
361		vk::VkSubmitInfo submitInfo =
362		{
363			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
364			DE_NULL,							// const void*				pNext;
365			0,									// deUint32					waitSemaphoreCount;
366			DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
367			(const vk::VkPipelineStageFlags*)DE_NULL,
368			1,									// deUint32					commandBufferCount;
369			&copyCmdBuffer.get(),				// const VkCommandBuffer*	pCommandBuffers;
370			0,									// deUint32					signalSemaphoreCount;
371			DE_NULL								// const VkSemaphore*		pSignalSemaphores;
372		};
373		m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
374
375		// TODO: make this less intrusive
376		VK_CHECK(m_vk.queueWaitIdle(queue));
377	}
378
379	deUint8* destPtr = reinterpret_cast<deUint8*>(stagingResource->getBoundMemory().getHostPtr());
380	deMemcpy(data, destPtr, static_cast<size_t>(bufferSize));
381}
382
383tcu::ConstPixelBufferAccess Image::readSurfaceLinear (vk::VkOffset3D				offset,
384													  int							width,
385													  int							height,
386													  int							depth,
387													  vk::VkImageAspectFlagBits		aspect,
388													  unsigned int					mipLevel,
389													  unsigned int					arrayElement)
390{
391	m_pixelAccessData.resize(width * height * vk::mapVkFormat(m_format).getPixelSize());
392	readLinear(offset, width, height, depth, mipLevel, arrayElement, aspect, m_pixelAccessData.data());
393	return tcu::ConstPixelBufferAccess(vk::mapVkFormat(m_format), width, height, 1, m_pixelAccessData.data());
394}
395
396void Image::readLinear (vk::VkOffset3D				offset,
397						int							width,
398						int							height,
399						int							depth,
400						unsigned int				mipLevel,
401						unsigned int				arrayElement,
402						vk::VkImageAspectFlagBits	aspect,
403						void *						data)
404{
405	vk::VkImageSubresource imageSubResource = { (vk::VkImageAspectFlags)aspect, mipLevel, arrayElement };
406
407	vk::VkSubresourceLayout imageLayout;
408	deMemset(&imageLayout, 0, sizeof(imageLayout));
409
410	m_vk.getImageSubresourceLayout(m_device, object(), &imageSubResource, &imageLayout);
411
412	const deUint8* srcPtr = reinterpret_cast<const deUint8*>(getBoundMemory().getHostPtr());
413	srcPtr += imageLayout.offset + getPixelOffset(offset, imageLayout.rowPitch, imageLayout.depthPitch, mipLevel, arrayElement);
414
415	MemoryOp::unpack(vk::mapVkFormat(m_format).getPixelSize(), width, height, depth,
416		imageLayout.rowPitch, imageLayout.depthPitch, srcPtr, data);
417}
418
419de::SharedPtr<Image> Image::copyToLinearImage (vk::VkQueue					queue,
420											   vk::Allocator&				allocator,
421											   vk::VkImageLayout			layout,
422											   vk::VkOffset3D				offset,
423											   int							width,
424											   int							height,
425											   int							depth,
426											   unsigned int					mipLevel,
427											   unsigned int					arrayElement,
428											   vk::VkImageAspectFlagBits	aspect,
429											   vk::VkImageType				type)
430{
431	de::SharedPtr<Image> stagingResource;
432	{
433		vk::VkExtent3D stagingExtent = {(deUint32)width, (deUint32)height, (deUint32)depth};
434		ImageCreateInfo stagingResourceCreateInfo(type, m_format, stagingExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
435												  vk::VK_IMAGE_TILING_LINEAR, vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
436
437		stagingResource = Image::createAndAlloc(m_vk, m_device, stagingResourceCreateInfo, allocator,
438												vk::MemoryRequirement::HostVisible);
439
440		//todo [scygan] get proper queueFamilyIndex
441		CmdPoolCreateInfo copyCmdPoolCreateInfo(0);
442		vk::Unique<vk::VkCommandPool> copyCmdPool(vk::createCommandPool(m_vk, m_device, &copyCmdPoolCreateInfo));
443
444		const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
445		{
446			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
447			DE_NULL,											// const void*				pNext;
448			*copyCmdPool,										// VkCommandPool			commandPool;
449			vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
450			1u,													// deUint32					bufferCount;
451		};
452		vk::Unique<vk::VkCommandBuffer> copyCmdBuffer(vk::allocateCommandBuffer(m_vk, m_device, &cmdBufferAllocateInfo));
453
454		CmdBufferBeginInfo beginInfo;
455		VK_CHECK(m_vk.beginCommandBuffer(*copyCmdBuffer, &beginInfo));
456
457		transition2DImage(m_vk, *copyCmdBuffer, stagingResource->object(), aspect, vk::VK_IMAGE_LAYOUT_UNDEFINED, vk::VK_IMAGE_LAYOUT_GENERAL);
458
459		const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
460		vk::VkImageCopy region = { { (vk::VkImageAspectFlags)aspect, mipLevel, arrayElement, 1}, offset, { (vk::VkImageAspectFlags)aspect, 0, 0, 1}, zeroOffset, {(deUint32)width, (deUint32)height, (deUint32)depth} };
461
462		m_vk.cmdCopyImage(*copyCmdBuffer, object(), layout, stagingResource->object(), vk::VK_IMAGE_LAYOUT_GENERAL, 1, &region);
463		VK_CHECK(m_vk.endCommandBuffer(*copyCmdBuffer));
464
465		vk::VkSubmitInfo submitInfo =
466		{
467			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
468			DE_NULL,							// const void*				pNext;
469			0,									// deUint32					waitSemaphoreCount;
470			DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
471			(const vk::VkPipelineStageFlags*)DE_NULL,
472			1,									// deUint32					commandBufferCount;
473			&copyCmdBuffer.get(),				// const VkCommandBuffer*	pCommandBuffers;
474			0,									// deUint32					signalSemaphoreCount;
475			DE_NULL								// const VkSemaphore*		pSignalSemaphores;
476		};
477		m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
478
479		// TODO: make this less intrusive
480		VK_CHECK(m_vk.queueWaitIdle(queue));
481	}
482	return stagingResource;
483}
484
485void Image::uploadVolume(const tcu::ConstPixelBufferAccess&	access,
486						 vk::VkQueue						queue,
487						 vk::Allocator&						allocator,
488						 vk::VkImageLayout					layout,
489						 vk::VkOffset3D						offset,
490						 vk::VkImageAspectFlagBits			aspect,
491						 unsigned int						mipLevel,
492						 unsigned int						arrayElement)
493{
494	if (aspect == vk::VK_IMAGE_ASPECT_COLOR_BIT)
495	{
496		upload(queue, allocator, layout, offset, access.getWidth(),
497		access.getHeight(), access.getDepth(), mipLevel, arrayElement, aspect, vk::VK_IMAGE_TYPE_3D,
498		access.getDataPtr());
499	}
500	if (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT || aspect == vk::VK_IMAGE_ASPECT_STENCIL_BIT)
501	{
502		uploadUsingBuffer(queue, allocator, layout, offset, access.getWidth(),
503		access.getHeight(), access.getDepth(), mipLevel, arrayElement, aspect, access.getDataPtr());
504	}
505}
506
507void Image::uploadSurface (const tcu::ConstPixelBufferAccess&	access,
508						   vk::VkQueue							queue,
509						   vk::Allocator&						allocator,
510						   vk::VkImageLayout					layout,
511						   vk::VkOffset3D						offset,
512						   vk::VkImageAspectFlagBits			aspect,
513						   unsigned int							mipLevel,
514						   unsigned int							arrayElement)
515{
516	if (aspect == vk::VK_IMAGE_ASPECT_COLOR_BIT)
517	{
518		upload(queue, allocator, layout, offset, access.getWidth(),
519			access.getHeight(), access.getDepth(), mipLevel, arrayElement, aspect, vk::VK_IMAGE_TYPE_2D,
520			access.getDataPtr());
521	}
522	if (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT || aspect == vk::VK_IMAGE_ASPECT_STENCIL_BIT)
523	{
524		uploadUsingBuffer(queue, allocator, layout, offset, access.getWidth(),
525			access.getHeight(), access.getDepth(), mipLevel, arrayElement, aspect, access.getDataPtr());
526	}
527}
528
529void Image::uploadSurface1D (const tcu::ConstPixelBufferAccess&	access,
530							 vk::VkQueue						queue,
531							 vk::Allocator&						allocator,
532							 vk::VkImageLayout					layout,
533							 vk::VkOffset3D						offset,
534							 vk::VkImageAspectFlagBits			aspect,
535							 unsigned int						mipLevel,
536							 unsigned int						arrayElement)
537{
538	if (aspect == vk::VK_IMAGE_ASPECT_COLOR_BIT)
539	{
540		upload(queue, allocator, layout, offset, access.getWidth(),
541			access.getHeight(), access.getDepth(), mipLevel, arrayElement, aspect, vk::VK_IMAGE_TYPE_1D,
542			access.getDataPtr());
543	}
544	if (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT || aspect == vk::VK_IMAGE_ASPECT_STENCIL_BIT)
545	{
546		uploadUsingBuffer(queue, allocator, layout, offset, access.getWidth(),
547			access.getHeight(), access.getDepth(), mipLevel, arrayElement, aspect, access.getDataPtr());
548	}
549}
550
551void Image::uploadSurfaceLinear (const tcu::ConstPixelBufferAccess&	access,
552								 vk::VkOffset3D						offset,
553								 int								width,
554								 int								height,
555								 int								depth,
556								 vk::VkImageAspectFlagBits			aspect,
557								 unsigned int						mipLevel,
558								 unsigned int						arrayElement)
559{
560	uploadLinear(offset, width, height, depth, mipLevel, arrayElement, aspect, access.getDataPtr());
561}
562
563void Image::upload (vk::VkQueue					queue,
564					vk::Allocator&				allocator,
565					vk::VkImageLayout			layout,
566					vk::VkOffset3D				offset,
567					int							width,
568					int							height,
569					int							depth,
570					unsigned int				mipLevel,
571					unsigned int				arrayElement,
572					vk::VkImageAspectFlagBits	aspect,
573					vk::VkImageType				type,
574					const void *				data)
575{
576	DE_ASSERT(layout == vk::VK_IMAGE_LAYOUT_GENERAL || layout == vk::VK_IMAGE_LAYOUT_UNDEFINED || layout == vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
577
578	de::SharedPtr<Image> stagingResource;
579	vk::VkExtent3D extent = {(deUint32)width, (deUint32)height, (deUint32)depth};
580	ImageCreateInfo stagingResourceCreateInfo(
581		type, m_format, extent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
582		vk::VK_IMAGE_TILING_LINEAR, vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
583
584	stagingResource = Image::createAndAlloc(m_vk, m_device, stagingResourceCreateInfo, allocator,
585								vk::MemoryRequirement::HostVisible);
586
587	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
588	stagingResource->uploadLinear(zeroOffset, width, height, depth, 0, 0, aspect, data);
589
590	{
591		//todo [scygan] get proper queueFamilyIndex
592		CmdPoolCreateInfo copyCmdPoolCreateInfo(0);
593		vk::Unique<vk::VkCommandPool> copyCmdPool(vk::createCommandPool(m_vk, m_device, &copyCmdPoolCreateInfo));
594
595		const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
596		{
597			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
598			DE_NULL,											// const void*				pNext;
599			*copyCmdPool,										// VkCommandPool			commandPool;
600			vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
601			1u,													// deUint32					bufferCount;
602		};
603
604		vk::Unique<vk::VkCommandBuffer> copyCmdBuffer(vk::allocateCommandBuffer(m_vk, m_device, &cmdBufferAllocateInfo));
605
606		CmdBufferBeginInfo beginInfo;
607		VK_CHECK(m_vk.beginCommandBuffer(*copyCmdBuffer, &beginInfo));
608
609		if (layout == vk::VK_IMAGE_LAYOUT_UNDEFINED)
610		{
611			layout = vk::VK_IMAGE_LAYOUT_GENERAL;
612
613			vk::VkImageMemoryBarrier barrier;
614			barrier.sType = vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
615			barrier.pNext = DE_NULL;
616			barrier.srcAccessMask = 0;
617			barrier.dstAccessMask = 0;
618			barrier.oldLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
619			barrier.newLayout = vk::VK_IMAGE_LAYOUT_GENERAL;
620			barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
621			barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
622			barrier.image = object();
623
624			barrier.subresourceRange.aspectMask = aspect;
625			barrier.subresourceRange.baseMipLevel = 0;
626			barrier.subresourceRange.levelCount = m_levelCount;
627			barrier.subresourceRange.baseArrayLayer = 0;
628			barrier.subresourceRange.layerCount = m_layerCount;
629
630			m_vk.cmdPipelineBarrier(*copyCmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
631									0, (const vk::VkMemoryBarrier*)DE_NULL,
632									0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
633									1, &barrier);
634		}
635
636		transition2DImage(m_vk, *copyCmdBuffer, stagingResource->object(), aspect, vk::VK_IMAGE_LAYOUT_UNDEFINED, vk::VK_IMAGE_LAYOUT_GENERAL);
637
638		vk::VkImageCopy region = {{ (vk::VkImageAspectFlags)aspect, 0, 0, 1},
639									zeroOffset,
640									{ (vk::VkImageAspectFlags)aspect, mipLevel, arrayElement, 1},
641									offset,
642									{(deUint32)width, (deUint32)height, (deUint32)depth}};
643
644		m_vk.cmdCopyImage(*copyCmdBuffer, stagingResource->object(),
645								vk::VK_IMAGE_LAYOUT_GENERAL, object(), layout, 1, &region);
646		VK_CHECK(m_vk.endCommandBuffer(*copyCmdBuffer));
647
648		vk::VkSubmitInfo submitInfo =
649		{
650			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
651			DE_NULL,							// const void*				pNext;
652			0,									// deUint32					waitSemaphoreCount;
653			DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
654			(const vk::VkPipelineStageFlags*)DE_NULL,
655			1,									// deUint32					commandBufferCount;
656			&copyCmdBuffer.get(),				// const VkCommandBuffer*	pCommandBuffers;
657			0,									// deUint32					signalSemaphoreCount;
658			DE_NULL								// const VkSemaphore*		pSignalSemaphores;
659		};
660		m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
661
662		// TODO: make this less intrusive
663		VK_CHECK(m_vk.queueWaitIdle(queue));
664	}
665}
666
667void Image::uploadUsingBuffer (vk::VkQueue					queue,
668							   vk::Allocator&				allocator,
669							   vk::VkImageLayout			layout,
670							   vk::VkOffset3D				offset,
671							   int							width,
672							   int							height,
673							   int							depth,
674							   unsigned int					mipLevel,
675							   unsigned int					arrayElement,
676							   vk::VkImageAspectFlagBits	aspect,
677							   const void *					data)
678{
679	DE_ASSERT(layout == vk::VK_IMAGE_LAYOUT_GENERAL || layout == vk::VK_IMAGE_LAYOUT_UNDEFINED || layout == vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
680
681	de::SharedPtr<Buffer> stagingResource;
682	bool isCombinedType = isCombinedDepthStencilType(vk::mapVkFormat(m_format).type);
683	vk::VkDeviceSize bufferSize = 0;
684	if (!isCombinedType)
685		bufferSize = vk::mapVkFormat(m_format).getPixelSize() *width*height*depth;
686	if (isCombinedType)
687	{
688		int pixelSize = 0;
689		switch (m_format)
690		{
691			case vk::VK_FORMAT_D16_UNORM_S8_UINT:
692				pixelSize = (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT) ? 2 : 1;
693				break;
694			case  vk::VK_FORMAT_D32_SFLOAT_S8_UINT:
695				pixelSize = (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT) ? 4 : 1;
696				break;
697			case vk::VK_FORMAT_X8_D24_UNORM_PACK32:
698			case vk::VK_FORMAT_D24_UNORM_S8_UINT:
699				pixelSize = (aspect == vk::VK_IMAGE_ASPECT_DEPTH_BIT) ? 3 : 1;
700				break;
701
702			default:
703				DE_FATAL("Not implemented");
704		}
705		bufferSize = pixelSize*width*height*depth;
706	}
707	BufferCreateInfo stagingBufferResourceCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
708	stagingResource = Buffer::createAndAlloc(m_vk, m_device, stagingBufferResourceCreateInfo, allocator, vk::MemoryRequirement::HostVisible);
709	deUint8* destPtr = reinterpret_cast<deUint8*>(stagingResource->getBoundMemory().getHostPtr());
710	deMemcpy(destPtr, data, static_cast<size_t>(bufferSize));
711	vk::flushMappedMemoryRange(m_vk, m_device, stagingResource->getBoundMemory().getMemory(), stagingResource->getBoundMemory().getOffset(), bufferSize);
712	{
713		//todo [scygan] get proper queueFamilyIndex
714		CmdPoolCreateInfo copyCmdPoolCreateInfo(0);
715		vk::Unique<vk::VkCommandPool> copyCmdPool(vk::createCommandPool(m_vk, m_device, &copyCmdPoolCreateInfo));
716
717		const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
718		{
719			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
720			DE_NULL,											// const void*				pNext;
721			*copyCmdPool,										// VkCommandPool			commandPool;
722			vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
723			1u,													// deUint32					bufferCount;
724		};
725		vk::Unique<vk::VkCommandBuffer> copyCmdBuffer(vk::allocateCommandBuffer(m_vk, m_device, &cmdBufferAllocateInfo));
726
727		CmdBufferBeginInfo beginInfo;
728		VK_CHECK(m_vk.beginCommandBuffer(*copyCmdBuffer, &beginInfo));
729
730		if (layout == vk::VK_IMAGE_LAYOUT_UNDEFINED)
731		{
732			layout = vk::VK_IMAGE_LAYOUT_GENERAL;
733
734			vk::VkImageMemoryBarrier barrier;
735			barrier.sType = vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
736			barrier.pNext = DE_NULL;
737			barrier.srcAccessMask = 0;
738			barrier.dstAccessMask = 0;
739			barrier.oldLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
740			barrier.newLayout = vk::VK_IMAGE_LAYOUT_GENERAL;
741			barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
742			barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
743			barrier.image = object();
744
745			barrier.subresourceRange.aspectMask = aspect;
746			barrier.subresourceRange.baseMipLevel = 0;
747			barrier.subresourceRange.levelCount = m_levelCount;
748			barrier.subresourceRange.baseArrayLayer = 0;
749			barrier.subresourceRange.layerCount = m_layerCount;
750
751			m_vk.cmdPipelineBarrier(*copyCmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
752									0, (const vk::VkMemoryBarrier*)DE_NULL,
753									0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
754									1, &barrier);
755		}
756
757		vk::VkBufferImageCopy region = {
758			0, 0, 0,
759			{ (vk::VkImageAspectFlags)aspect, mipLevel, arrayElement, 1 },
760			offset,
761			{ (deUint32)width, (deUint32)height, (deUint32)depth }
762		};
763
764		m_vk.cmdCopyBufferToImage(*copyCmdBuffer, stagingResource->object(),
765			object(), layout, 1, &region);
766		VK_CHECK(m_vk.endCommandBuffer(*copyCmdBuffer));
767
768		vk::VkSubmitInfo submitInfo =
769		{
770			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
771			DE_NULL,							// const void*				pNext;
772			0,									// deUint32					waitSemaphoreCount;
773			DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
774			(const vk::VkPipelineStageFlags*)DE_NULL,
775			1,									// deUint32					commandBufferCount;
776			&copyCmdBuffer.get(),				// const VkCommandBuffer*	pCommandBuffers;
777			0,									// deUint32					signalSemaphoreCount;
778			DE_NULL								// const VkSemaphore*		pSignalSemaphores;
779		};
780		m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
781
782		// TODO: make this less intrusive
783		VK_CHECK(m_vk.queueWaitIdle(queue));
784	}
785}
786
787void Image::uploadLinear (vk::VkOffset3D			offset,
788						  int						width,
789						  int						height,
790						  int						depth,
791						  unsigned int				mipLevel,
792						  unsigned int				arrayElement,
793						  vk::VkImageAspectFlagBits	aspect,
794						  const void *				data)
795{
796	vk::VkSubresourceLayout imageLayout;
797
798	vk::VkImageSubresource imageSubResource = { (vk::VkImageAspectFlags)aspect, mipLevel, arrayElement};
799
800	m_vk.getImageSubresourceLayout(m_device, object(), &imageSubResource,
801													&imageLayout);
802
803	deUint8* destPtr = reinterpret_cast<deUint8*>(getBoundMemory().getHostPtr());
804
805	destPtr += imageLayout.offset + getPixelOffset(offset, imageLayout.rowPitch, imageLayout.depthPitch, mipLevel, arrayElement);
806
807	MemoryOp::pack(vk::mapVkFormat(m_format).getPixelSize(), width, height, depth,
808		imageLayout.rowPitch, imageLayout.depthPitch, data, destPtr);
809}
810
811vk::VkDeviceSize Image::getPixelOffset (vk::VkOffset3D		offset,
812										vk::VkDeviceSize	rowPitch,
813										vk::VkDeviceSize	depthPitch,
814										unsigned int		level,
815										unsigned int		layer)
816{
817	DE_ASSERT(level < m_levelCount);
818	DE_ASSERT(layer < m_layerCount);
819
820	vk::VkDeviceSize mipLevelSizes[32];
821	vk::VkDeviceSize mipLevelRectSizes[32];
822	tcu::IVec3 mipExtend
823	= tcu::IVec3(m_extent.width, m_extent.height, m_extent.depth);
824
825	vk::VkDeviceSize arrayElemSize = 0;
826	for (unsigned int i = 0; i < m_levelCount && (mipExtend[0] > 1 || mipExtend[1] > 1 || mipExtend[2] > 1); ++i)
827	{
828		// Rect size is just a 3D image size;
829		mipLevelSizes[i] = mipExtend[2] * depthPitch;
830
831		arrayElemSize += mipLevelSizes[0];
832
833		mipExtend = tcu::max(mipExtend / 2, tcu::IVec3(1));
834	}
835
836	vk::VkDeviceSize pixelOffset = layer * arrayElemSize;
837	for (size_t i = 0; i < level; ++i) {
838		pixelOffset += mipLevelSizes[i];
839	}
840	pixelOffset += offset.z * mipLevelRectSizes[level];
841	pixelOffset += offset.y * rowPitch;
842	pixelOffset += offset.x;
843
844	return pixelOffset;
845}
846
847void Image::bindMemory (de::MovePtr<vk::Allocation> allocation)
848{
849	DE_ASSERT(allocation);
850	VK_CHECK(m_vk.bindImageMemory(m_device, *m_object, allocation->getMemory(), allocation->getOffset()));
851
852	DE_ASSERT(!m_allocation);
853	m_allocation = allocation;
854}
855
856de::SharedPtr<Image> Image::createAndAlloc(const vk::DeviceInterface&	vk,
857										   vk::VkDevice					device,
858										   const vk::VkImageCreateInfo& createInfo,
859										   vk::Allocator&				allocator,
860										   vk::MemoryRequirement		memoryRequirement)
861{
862	de::SharedPtr<Image> ret = create(vk, device, createInfo);
863
864	vk::VkMemoryRequirements imageRequirements = vk::getImageMemoryRequirements(vk, device, ret->object());
865	ret->bindMemory(allocator.allocate(imageRequirements, memoryRequirement));
866	return ret;
867}
868
869de::SharedPtr<Image> Image::create(const vk::DeviceInterface&	vk,
870								   vk::VkDevice					device,
871								   const vk::VkImageCreateInfo	&createInfo)
872{
873	return de::SharedPtr<Image>(new Image(vk, device, createInfo.format, createInfo.extent,
874								createInfo.mipLevels, createInfo.arrayLayers,
875								vk::createImage(vk, device, &createInfo)));
876}
877
878void transition2DImage (const vk::DeviceInterface&	vk,
879						vk::VkCommandBuffer			cmdBuffer,
880						vk::VkImage					image,
881						vk::VkImageAspectFlags		aspectMask,
882						vk::VkImageLayout			oldLayout,
883						vk::VkImageLayout			newLayout,
884						vk::VkAccessFlags			srcAccessMask,
885						vk::VkAccessFlags			dstAccessMask)
886{
887	vk::VkImageMemoryBarrier barrier;
888	barrier.sType							= vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
889	barrier.pNext							= DE_NULL;
890	barrier.srcAccessMask					= srcAccessMask;
891	barrier.dstAccessMask					= dstAccessMask;
892	barrier.oldLayout						= oldLayout;
893	barrier.newLayout						= newLayout;
894	barrier.srcQueueFamilyIndex				= VK_QUEUE_FAMILY_IGNORED;
895	barrier.dstQueueFamilyIndex				= VK_QUEUE_FAMILY_IGNORED;
896	barrier.image							= image;
897	barrier.subresourceRange.aspectMask		= aspectMask;
898	barrier.subresourceRange.baseMipLevel	= 0;
899	barrier.subresourceRange.levelCount		= 1;
900	barrier.subresourceRange.baseArrayLayer = 0;
901	barrier.subresourceRange.layerCount		= 1;
902
903	vk.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
904						  0, (const vk::VkMemoryBarrier*)DE_NULL,
905						  0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
906						  1, &barrier);
907}
908
909void initialTransitionColor2DImage (const vk::DeviceInterface &vk, vk::VkCommandBuffer cmdBuffer, vk::VkImage image, vk::VkImageLayout layout)
910{
911	transition2DImage(vk, cmdBuffer, image, vk::VK_IMAGE_ASPECT_COLOR_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED, layout);
912}
913
914void initialTransitionDepth2DImage (const vk::DeviceInterface &vk, vk::VkCommandBuffer cmdBuffer, vk::VkImage image, vk::VkImageLayout layout)
915{
916	transition2DImage(vk, cmdBuffer, image, vk::VK_IMAGE_ASPECT_DEPTH_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED, layout);
917}
918
919void initialTransitionStencil2DImage (const vk::DeviceInterface &vk, vk::VkCommandBuffer cmdBuffer, vk::VkImage image, vk::VkImageLayout layout)
920{
921	transition2DImage(vk, cmdBuffer, image, vk::VK_IMAGE_ASPECT_STENCIL_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED, layout);
922}
923
924void initialTransitionDepthStencil2DImage (const vk::DeviceInterface&	vk,
925										   vk::VkCommandBuffer			cmdBuffer,
926										   vk::VkImage					image,
927										   vk::VkImageLayout			layout,
928										   vk::VkAccessFlags			srcAccessMask,
929										   vk::VkAccessFlags			dstAccessMask)
930{
931	transition2DImage(vk, cmdBuffer, image, vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED, layout, srcAccessMask, dstAccessMask);
932}
933
934} // Draw
935} // vkt
936