xref: /aosp_15_r20/external/swiftshader/src/Device/Blitter.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker //    http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker 
15*03ce13f7SAndroid Build Coastguard Worker #include "Blitter.hpp"
16*03ce13f7SAndroid Build Coastguard Worker 
17*03ce13f7SAndroid Build Coastguard Worker #include "Pipeline/ShaderCore.hpp"
18*03ce13f7SAndroid Build Coastguard Worker #include "Reactor/Reactor.hpp"
19*03ce13f7SAndroid Build Coastguard Worker #include "System/CPUID.hpp"
20*03ce13f7SAndroid Build Coastguard Worker #include "System/Debug.hpp"
21*03ce13f7SAndroid Build Coastguard Worker #include "System/Half.hpp"
22*03ce13f7SAndroid Build Coastguard Worker #include "System/Memory.hpp"
23*03ce13f7SAndroid Build Coastguard Worker #include "Vulkan/VkImage.hpp"
24*03ce13f7SAndroid Build Coastguard Worker #include "Vulkan/VkImageView.hpp"
25*03ce13f7SAndroid Build Coastguard Worker 
26*03ce13f7SAndroid Build Coastguard Worker #include <utility>
27*03ce13f7SAndroid Build Coastguard Worker 
28*03ce13f7SAndroid Build Coastguard Worker #if defined(__i386__) || defined(__x86_64__)
29*03ce13f7SAndroid Build Coastguard Worker #	include <xmmintrin.h>
30*03ce13f7SAndroid Build Coastguard Worker #	include <emmintrin.h>
31*03ce13f7SAndroid Build Coastguard Worker #endif
32*03ce13f7SAndroid Build Coastguard Worker 
33*03ce13f7SAndroid Build Coastguard Worker namespace sw {
34*03ce13f7SAndroid Build Coastguard Worker 
PackFields(const rr::Int4 & ints,const sw::int4 shifts)35*03ce13f7SAndroid Build Coastguard Worker static rr::RValue<rr::Int> PackFields(const rr::Int4 &ints, const sw::int4 shifts)
36*03ce13f7SAndroid Build Coastguard Worker {
37*03ce13f7SAndroid Build Coastguard Worker 	return (rr::Int(ints.x) << shifts[0]) |
38*03ce13f7SAndroid Build Coastguard Worker 	       (rr::Int(ints.y) << shifts[1]) |
39*03ce13f7SAndroid Build Coastguard Worker 	       (rr::Int(ints.z) << shifts[2]) |
40*03ce13f7SAndroid Build Coastguard Worker 	       (rr::Int(ints.w) << shifts[3]);
41*03ce13f7SAndroid Build Coastguard Worker }
42*03ce13f7SAndroid Build Coastguard Worker 
Blitter()43*03ce13f7SAndroid Build Coastguard Worker Blitter::Blitter()
44*03ce13f7SAndroid Build Coastguard Worker     : blitMutex()
45*03ce13f7SAndroid Build Coastguard Worker     , blitCache(1024)
46*03ce13f7SAndroid Build Coastguard Worker     , cornerUpdateMutex()
47*03ce13f7SAndroid Build Coastguard Worker     , cornerUpdateCache(64)  // We only need one of these per format
48*03ce13f7SAndroid Build Coastguard Worker {
49*03ce13f7SAndroid Build Coastguard Worker }
50*03ce13f7SAndroid Build Coastguard Worker 
~Blitter()51*03ce13f7SAndroid Build Coastguard Worker Blitter::~Blitter()
52*03ce13f7SAndroid Build Coastguard Worker {
53*03ce13f7SAndroid Build Coastguard Worker }
54*03ce13f7SAndroid Build Coastguard Worker 
clear(const void * pixel,vk::Format format,vk::Image * dest,const vk::Format & viewFormat,const VkImageSubresourceRange & subresourceRange,const VkRect2D * renderArea)55*03ce13f7SAndroid Build Coastguard Worker void Blitter::clear(const void *pixel, vk::Format format, vk::Image *dest, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea)
56*03ce13f7SAndroid Build Coastguard Worker {
57*03ce13f7SAndroid Build Coastguard Worker 	VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask);
58*03ce13f7SAndroid Build Coastguard Worker 	vk::Format dstFormat = viewFormat.getAspectFormat(aspect);
59*03ce13f7SAndroid Build Coastguard Worker 	if(dstFormat == VK_FORMAT_UNDEFINED)
60*03ce13f7SAndroid Build Coastguard Worker 	{
61*03ce13f7SAndroid Build Coastguard Worker 		return;
62*03ce13f7SAndroid Build Coastguard Worker 	}
63*03ce13f7SAndroid Build Coastguard Worker 
64*03ce13f7SAndroid Build Coastguard Worker 	VkClearValue clampedPixel;
65*03ce13f7SAndroid Build Coastguard Worker 	if(viewFormat.isSignedNormalized() || viewFormat.isUnsignedNormalized())
66*03ce13f7SAndroid Build Coastguard Worker 	{
67*03ce13f7SAndroid Build Coastguard Worker 		const float minValue = viewFormat.isSignedNormalized() ? -1.0f : 0.0f;
68*03ce13f7SAndroid Build Coastguard Worker 
69*03ce13f7SAndroid Build Coastguard Worker 		if(aspect & VK_IMAGE_ASPECT_COLOR_BIT)
70*03ce13f7SAndroid Build Coastguard Worker 		{
71*03ce13f7SAndroid Build Coastguard Worker 			memcpy(clampedPixel.color.float32, pixel, sizeof(VkClearColorValue));
72*03ce13f7SAndroid Build Coastguard Worker 			clampedPixel.color.float32[0] = sw::clamp(clampedPixel.color.float32[0], minValue, 1.0f);
73*03ce13f7SAndroid Build Coastguard Worker 			clampedPixel.color.float32[1] = sw::clamp(clampedPixel.color.float32[1], minValue, 1.0f);
74*03ce13f7SAndroid Build Coastguard Worker 			clampedPixel.color.float32[2] = sw::clamp(clampedPixel.color.float32[2], minValue, 1.0f);
75*03ce13f7SAndroid Build Coastguard Worker 			clampedPixel.color.float32[3] = sw::clamp(clampedPixel.color.float32[3], minValue, 1.0f);
76*03ce13f7SAndroid Build Coastguard Worker 			pixel = clampedPixel.color.float32;
77*03ce13f7SAndroid Build Coastguard Worker 		}
78*03ce13f7SAndroid Build Coastguard Worker 
79*03ce13f7SAndroid Build Coastguard Worker 		// Stencil never requires clamping, so we can check for Depth only
80*03ce13f7SAndroid Build Coastguard Worker 		if(aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
81*03ce13f7SAndroid Build Coastguard Worker 		{
82*03ce13f7SAndroid Build Coastguard Worker 			memcpy(&(clampedPixel.depthStencil), pixel, sizeof(VkClearDepthStencilValue));
83*03ce13f7SAndroid Build Coastguard Worker 			clampedPixel.depthStencil.depth = sw::clamp(clampedPixel.depthStencil.depth, minValue, 1.0f);
84*03ce13f7SAndroid Build Coastguard Worker 			pixel = &(clampedPixel.depthStencil);
85*03ce13f7SAndroid Build Coastguard Worker 		}
86*03ce13f7SAndroid Build Coastguard Worker 	}
87*03ce13f7SAndroid Build Coastguard Worker 
88*03ce13f7SAndroid Build Coastguard Worker 	if(fastClear(pixel, format, dest, dstFormat, subresourceRange, renderArea))
89*03ce13f7SAndroid Build Coastguard Worker 	{
90*03ce13f7SAndroid Build Coastguard Worker 		return;
91*03ce13f7SAndroid Build Coastguard Worker 	}
92*03ce13f7SAndroid Build Coastguard Worker 
93*03ce13f7SAndroid Build Coastguard Worker 	State state(format, dstFormat, 1, dest->getSampleCount(), Options{ 0xF });
94*03ce13f7SAndroid Build Coastguard Worker 	auto blitRoutine = getBlitRoutine(state);
95*03ce13f7SAndroid Build Coastguard Worker 	if(!blitRoutine)
96*03ce13f7SAndroid Build Coastguard Worker 	{
97*03ce13f7SAndroid Build Coastguard Worker 		return;
98*03ce13f7SAndroid Build Coastguard Worker 	}
99*03ce13f7SAndroid Build Coastguard Worker 
100*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource subres = {
101*03ce13f7SAndroid Build Coastguard Worker 		subresourceRange.aspectMask,
102*03ce13f7SAndroid Build Coastguard Worker 		subresourceRange.baseMipLevel,
103*03ce13f7SAndroid Build Coastguard Worker 		subresourceRange.baseArrayLayer
104*03ce13f7SAndroid Build Coastguard Worker 	};
105*03ce13f7SAndroid Build Coastguard Worker 
106*03ce13f7SAndroid Build Coastguard Worker 	uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange);
107*03ce13f7SAndroid Build Coastguard Worker 	uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange);
108*03ce13f7SAndroid Build Coastguard Worker 
109*03ce13f7SAndroid Build Coastguard Worker 	VkRect2D area = { { 0, 0 }, { 0, 0 } };
110*03ce13f7SAndroid Build Coastguard Worker 	if(renderArea)
111*03ce13f7SAndroid Build Coastguard Worker 	{
112*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(subresourceRange.levelCount == 1);
113*03ce13f7SAndroid Build Coastguard Worker 		area = *renderArea;
114*03ce13f7SAndroid Build Coastguard Worker 	}
115*03ce13f7SAndroid Build Coastguard Worker 
116*03ce13f7SAndroid Build Coastguard Worker 	for(; subres.mipLevel <= lastMipLevel; subres.mipLevel++)
117*03ce13f7SAndroid Build Coastguard Worker 	{
118*03ce13f7SAndroid Build Coastguard Worker 		VkExtent3D extent = dest->getMipLevelExtent(aspect, subres.mipLevel);
119*03ce13f7SAndroid Build Coastguard Worker 		if(!renderArea)
120*03ce13f7SAndroid Build Coastguard Worker 		{
121*03ce13f7SAndroid Build Coastguard Worker 			area.extent.width = extent.width;
122*03ce13f7SAndroid Build Coastguard Worker 			area.extent.height = extent.height;
123*03ce13f7SAndroid Build Coastguard Worker 		}
124*03ce13f7SAndroid Build Coastguard Worker 
125*03ce13f7SAndroid Build Coastguard Worker 		BlitData data = {
126*03ce13f7SAndroid Build Coastguard Worker 			pixel, nullptr,  // source, dest
127*03ce13f7SAndroid Build Coastguard Worker 
128*03ce13f7SAndroid Build Coastguard Worker 			assert_cast<uint32_t>(format.bytes()),                                  // sPitchB
129*03ce13f7SAndroid Build Coastguard Worker 			assert_cast<uint32_t>(dest->rowPitchBytes(aspect, subres.mipLevel)),    // dPitchB
130*03ce13f7SAndroid Build Coastguard Worker 			0,                                                                      // sSliceB (unused in clear operations)
131*03ce13f7SAndroid Build Coastguard Worker 			assert_cast<uint32_t>(dest->slicePitchBytes(aspect, subres.mipLevel)),  // dSliceB
132*03ce13f7SAndroid Build Coastguard Worker 
133*03ce13f7SAndroid Build Coastguard Worker 			0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f,  // x0, y0, z0, w, h, d
134*03ce13f7SAndroid Build Coastguard Worker 
135*03ce13f7SAndroid Build Coastguard Worker 			area.offset.x, static_cast<int>(area.offset.x + area.extent.width),   // x0d, x1d
136*03ce13f7SAndroid Build Coastguard Worker 			area.offset.y, static_cast<int>(area.offset.y + area.extent.height),  // y0d, y1d
137*03ce13f7SAndroid Build Coastguard Worker 			0, 1,                                                                 // z0d, z1d
138*03ce13f7SAndroid Build Coastguard Worker 
139*03ce13f7SAndroid Build Coastguard Worker 			0, 0, 0,  // sWidth, sHeight, sDepth
140*03ce13f7SAndroid Build Coastguard Worker 
141*03ce13f7SAndroid Build Coastguard Worker 			false,  // filter3D
142*03ce13f7SAndroid Build Coastguard Worker 		};
143*03ce13f7SAndroid Build Coastguard Worker 
144*03ce13f7SAndroid Build Coastguard Worker 		if(renderArea && dest->is3DSlice())
145*03ce13f7SAndroid Build Coastguard Worker 		{
146*03ce13f7SAndroid Build Coastguard Worker 			// Reinterpret layers as depth slices
147*03ce13f7SAndroid Build Coastguard Worker 			subres.arrayLayer = 0;
148*03ce13f7SAndroid Build Coastguard Worker 			for(uint32_t depth = subresourceRange.baseArrayLayer; depth <= lastLayer; depth++)
149*03ce13f7SAndroid Build Coastguard Worker 			{
150*03ce13f7SAndroid Build Coastguard Worker 				data.dest = dest->getTexelPointer({ 0, 0, static_cast<int32_t>(depth) }, subres);
151*03ce13f7SAndroid Build Coastguard Worker 				blitRoutine(&data);
152*03ce13f7SAndroid Build Coastguard Worker 			}
153*03ce13f7SAndroid Build Coastguard Worker 		}
154*03ce13f7SAndroid Build Coastguard Worker 		else
155*03ce13f7SAndroid Build Coastguard Worker 		{
156*03ce13f7SAndroid Build Coastguard Worker 			for(subres.arrayLayer = subresourceRange.baseArrayLayer; subres.arrayLayer <= lastLayer; subres.arrayLayer++)
157*03ce13f7SAndroid Build Coastguard Worker 			{
158*03ce13f7SAndroid Build Coastguard Worker 				for(uint32_t depth = 0; depth < extent.depth; depth++)
159*03ce13f7SAndroid Build Coastguard Worker 				{
160*03ce13f7SAndroid Build Coastguard Worker 					data.dest = dest->getTexelPointer({ 0, 0, static_cast<int32_t>(depth) }, subres);
161*03ce13f7SAndroid Build Coastguard Worker 
162*03ce13f7SAndroid Build Coastguard Worker 					blitRoutine(&data);
163*03ce13f7SAndroid Build Coastguard Worker 				}
164*03ce13f7SAndroid Build Coastguard Worker 			}
165*03ce13f7SAndroid Build Coastguard Worker 		}
166*03ce13f7SAndroid Build Coastguard Worker 	}
167*03ce13f7SAndroid Build Coastguard Worker 	dest->contentsChanged(subresourceRange);
168*03ce13f7SAndroid Build Coastguard Worker }
169*03ce13f7SAndroid Build Coastguard Worker 
fastClear(const void * clearValue,vk::Format clearFormat,vk::Image * dest,const vk::Format & viewFormat,const VkImageSubresourceRange & subresourceRange,const VkRect2D * renderArea)170*03ce13f7SAndroid Build Coastguard Worker bool Blitter::fastClear(const void *clearValue, vk::Format clearFormat, vk::Image *dest, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea)
171*03ce13f7SAndroid Build Coastguard Worker {
172*03ce13f7SAndroid Build Coastguard Worker 	if(clearFormat != VK_FORMAT_R32G32B32A32_SFLOAT &&
173*03ce13f7SAndroid Build Coastguard Worker 	   clearFormat != VK_FORMAT_D32_SFLOAT &&
174*03ce13f7SAndroid Build Coastguard Worker 	   clearFormat != VK_FORMAT_S8_UINT)
175*03ce13f7SAndroid Build Coastguard Worker 	{
176*03ce13f7SAndroid Build Coastguard Worker 		return false;
177*03ce13f7SAndroid Build Coastguard Worker 	}
178*03ce13f7SAndroid Build Coastguard Worker 
179*03ce13f7SAndroid Build Coastguard Worker 	union ClearValue
180*03ce13f7SAndroid Build Coastguard Worker 	{
181*03ce13f7SAndroid Build Coastguard Worker 		struct
182*03ce13f7SAndroid Build Coastguard Worker 		{
183*03ce13f7SAndroid Build Coastguard Worker 			float r;
184*03ce13f7SAndroid Build Coastguard Worker 			float g;
185*03ce13f7SAndroid Build Coastguard Worker 			float b;
186*03ce13f7SAndroid Build Coastguard Worker 			float a;
187*03ce13f7SAndroid Build Coastguard Worker 		};
188*03ce13f7SAndroid Build Coastguard Worker 
189*03ce13f7SAndroid Build Coastguard Worker 		float rgb[3];
190*03ce13f7SAndroid Build Coastguard Worker 
191*03ce13f7SAndroid Build Coastguard Worker 		float d;
192*03ce13f7SAndroid Build Coastguard Worker 		uint32_t d_as_u32;
193*03ce13f7SAndroid Build Coastguard Worker 
194*03ce13f7SAndroid Build Coastguard Worker 		uint32_t s;
195*03ce13f7SAndroid Build Coastguard Worker 	};
196*03ce13f7SAndroid Build Coastguard Worker 
197*03ce13f7SAndroid Build Coastguard Worker 	const ClearValue &c = *reinterpret_cast<const ClearValue *>(clearValue);
198*03ce13f7SAndroid Build Coastguard Worker 
199*03ce13f7SAndroid Build Coastguard Worker 	uint32_t packed = 0;
200*03ce13f7SAndroid Build Coastguard Worker 
201*03ce13f7SAndroid Build Coastguard Worker 	VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask);
202*03ce13f7SAndroid Build Coastguard Worker 	switch(viewFormat)
203*03ce13f7SAndroid Build Coastguard Worker 	{
204*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R5G6B5_UNORM_PACK16:
205*03ce13f7SAndroid Build Coastguard Worker 		packed = ((uint16_t)(31 * c.b + 0.5f) << 0) |
206*03ce13f7SAndroid Build Coastguard Worker 		         ((uint16_t)(63 * c.g + 0.5f) << 5) |
207*03ce13f7SAndroid Build Coastguard Worker 		         ((uint16_t)(31 * c.r + 0.5f) << 11);
208*03ce13f7SAndroid Build Coastguard Worker 		break;
209*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B5G6R5_UNORM_PACK16:
210*03ce13f7SAndroid Build Coastguard Worker 		packed = ((uint16_t)(31 * c.r + 0.5f) << 0) |
211*03ce13f7SAndroid Build Coastguard Worker 		         ((uint16_t)(63 * c.g + 0.5f) << 5) |
212*03ce13f7SAndroid Build Coastguard Worker 		         ((uint16_t)(31 * c.b + 0.5f) << 11);
213*03ce13f7SAndroid Build Coastguard Worker 		break;
214*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
215*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
216*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UNORM:
217*03ce13f7SAndroid Build Coastguard Worker 		packed = ((uint32_t)(255 * c.a + 0.5f) << 24) |
218*03ce13f7SAndroid Build Coastguard Worker 		         ((uint32_t)(255 * c.b + 0.5f) << 16) |
219*03ce13f7SAndroid Build Coastguard Worker 		         ((uint32_t)(255 * c.g + 0.5f) << 8) |
220*03ce13f7SAndroid Build Coastguard Worker 		         ((uint32_t)(255 * c.r + 0.5f) << 0);
221*03ce13f7SAndroid Build Coastguard Worker 		break;
222*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_UNORM:
223*03ce13f7SAndroid Build Coastguard Worker 		packed = ((uint32_t)(255 * c.a + 0.5f) << 24) |
224*03ce13f7SAndroid Build Coastguard Worker 		         ((uint32_t)(255 * c.r + 0.5f) << 16) |
225*03ce13f7SAndroid Build Coastguard Worker 		         ((uint32_t)(255 * c.g + 0.5f) << 8) |
226*03ce13f7SAndroid Build Coastguard Worker 		         ((uint32_t)(255 * c.b + 0.5f) << 0);
227*03ce13f7SAndroid Build Coastguard Worker 		break;
228*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
229*03ce13f7SAndroid Build Coastguard Worker 		packed = R11G11B10F(c.rgb);
230*03ce13f7SAndroid Build Coastguard Worker 		break;
231*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
232*03ce13f7SAndroid Build Coastguard Worker 		packed = RGB9E5(c.rgb);
233*03ce13f7SAndroid Build Coastguard Worker 		break;
234*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_D32_SFLOAT:
235*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(clearFormat == VK_FORMAT_D32_SFLOAT);
236*03ce13f7SAndroid Build Coastguard Worker 		packed = c.d_as_u32;  // float reinterpreted as uint32
237*03ce13f7SAndroid Build Coastguard Worker 		break;
238*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_S8_UINT:
239*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(clearFormat == VK_FORMAT_S8_UINT);
240*03ce13f7SAndroid Build Coastguard Worker 		packed = static_cast<uint8_t>(c.s);
241*03ce13f7SAndroid Build Coastguard Worker 		break;
242*03ce13f7SAndroid Build Coastguard Worker 	default:
243*03ce13f7SAndroid Build Coastguard Worker 		return false;
244*03ce13f7SAndroid Build Coastguard Worker 	}
245*03ce13f7SAndroid Build Coastguard Worker 
246*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource subres = {
247*03ce13f7SAndroid Build Coastguard Worker 		subresourceRange.aspectMask,
248*03ce13f7SAndroid Build Coastguard Worker 		subresourceRange.baseMipLevel,
249*03ce13f7SAndroid Build Coastguard Worker 		subresourceRange.baseArrayLayer
250*03ce13f7SAndroid Build Coastguard Worker 	};
251*03ce13f7SAndroid Build Coastguard Worker 	uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange);
252*03ce13f7SAndroid Build Coastguard Worker 	uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange);
253*03ce13f7SAndroid Build Coastguard Worker 
254*03ce13f7SAndroid Build Coastguard Worker 	VkRect2D area = { { 0, 0 }, { 0, 0 } };
255*03ce13f7SAndroid Build Coastguard Worker 	if(renderArea)
256*03ce13f7SAndroid Build Coastguard Worker 	{
257*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(subresourceRange.levelCount == 1);
258*03ce13f7SAndroid Build Coastguard Worker 		area = *renderArea;
259*03ce13f7SAndroid Build Coastguard Worker 	}
260*03ce13f7SAndroid Build Coastguard Worker 
261*03ce13f7SAndroid Build Coastguard Worker 	for(; subres.mipLevel <= lastMipLevel; subres.mipLevel++)
262*03ce13f7SAndroid Build Coastguard Worker 	{
263*03ce13f7SAndroid Build Coastguard Worker 		int rowPitchBytes = dest->rowPitchBytes(aspect, subres.mipLevel);
264*03ce13f7SAndroid Build Coastguard Worker 		int slicePitchBytes = dest->slicePitchBytes(aspect, subres.mipLevel);
265*03ce13f7SAndroid Build Coastguard Worker 		VkExtent3D extent = dest->getMipLevelExtent(aspect, subres.mipLevel);
266*03ce13f7SAndroid Build Coastguard Worker 		if(!renderArea)
267*03ce13f7SAndroid Build Coastguard Worker 		{
268*03ce13f7SAndroid Build Coastguard Worker 			area.extent.width = extent.width;
269*03ce13f7SAndroid Build Coastguard Worker 			area.extent.height = extent.height;
270*03ce13f7SAndroid Build Coastguard Worker 		}
271*03ce13f7SAndroid Build Coastguard Worker 		if(dest->is3DSlice())
272*03ce13f7SAndroid Build Coastguard Worker 		{
273*03ce13f7SAndroid Build Coastguard Worker 			extent.depth = 1;  // The 3D image is instead interpreted as a 2D image with layers
274*03ce13f7SAndroid Build Coastguard Worker 		}
275*03ce13f7SAndroid Build Coastguard Worker 
276*03ce13f7SAndroid Build Coastguard Worker 		for(subres.arrayLayer = subresourceRange.baseArrayLayer; subres.arrayLayer <= lastLayer; subres.arrayLayer++)
277*03ce13f7SAndroid Build Coastguard Worker 		{
278*03ce13f7SAndroid Build Coastguard Worker 			for(uint32_t depth = 0; depth < extent.depth; depth++)
279*03ce13f7SAndroid Build Coastguard Worker 			{
280*03ce13f7SAndroid Build Coastguard Worker 				uint8_t *slice = (uint8_t *)dest->getTexelPointer(
281*03ce13f7SAndroid Build Coastguard Worker 				    { area.offset.x, area.offset.y, static_cast<int32_t>(depth) }, subres);
282*03ce13f7SAndroid Build Coastguard Worker 
283*03ce13f7SAndroid Build Coastguard Worker 				for(int j = 0; j < dest->getSampleCount(); j++)
284*03ce13f7SAndroid Build Coastguard Worker 				{
285*03ce13f7SAndroid Build Coastguard Worker 					uint8_t *d = slice;
286*03ce13f7SAndroid Build Coastguard Worker 
287*03ce13f7SAndroid Build Coastguard Worker 					switch(viewFormat.bytes())
288*03ce13f7SAndroid Build Coastguard Worker 					{
289*03ce13f7SAndroid Build Coastguard Worker 					case 4:
290*03ce13f7SAndroid Build Coastguard Worker 						for(uint32_t i = 0; i < area.extent.height; i++)
291*03ce13f7SAndroid Build Coastguard Worker 						{
292*03ce13f7SAndroid Build Coastguard Worker 							ASSERT(d < dest->end());
293*03ce13f7SAndroid Build Coastguard Worker 							sw::clear((uint32_t *)d, packed, area.extent.width);
294*03ce13f7SAndroid Build Coastguard Worker 							d += rowPitchBytes;
295*03ce13f7SAndroid Build Coastguard Worker 						}
296*03ce13f7SAndroid Build Coastguard Worker 						break;
297*03ce13f7SAndroid Build Coastguard Worker 					case 2:
298*03ce13f7SAndroid Build Coastguard Worker 						for(uint32_t i = 0; i < area.extent.height; i++)
299*03ce13f7SAndroid Build Coastguard Worker 						{
300*03ce13f7SAndroid Build Coastguard Worker 							ASSERT(d < dest->end());
301*03ce13f7SAndroid Build Coastguard Worker 							sw::clear((uint16_t *)d, static_cast<uint16_t>(packed), area.extent.width);
302*03ce13f7SAndroid Build Coastguard Worker 							d += rowPitchBytes;
303*03ce13f7SAndroid Build Coastguard Worker 						}
304*03ce13f7SAndroid Build Coastguard Worker 						break;
305*03ce13f7SAndroid Build Coastguard Worker 					case 1:
306*03ce13f7SAndroid Build Coastguard Worker 						for(uint32_t i = 0; i < area.extent.height; i++)
307*03ce13f7SAndroid Build Coastguard Worker 						{
308*03ce13f7SAndroid Build Coastguard Worker 							ASSERT(d < dest->end());
309*03ce13f7SAndroid Build Coastguard Worker 							memset(d, packed, area.extent.width);
310*03ce13f7SAndroid Build Coastguard Worker 							d += rowPitchBytes;
311*03ce13f7SAndroid Build Coastguard Worker 						}
312*03ce13f7SAndroid Build Coastguard Worker 						break;
313*03ce13f7SAndroid Build Coastguard Worker 					default:
314*03ce13f7SAndroid Build Coastguard Worker 						assert(false);
315*03ce13f7SAndroid Build Coastguard Worker 					}
316*03ce13f7SAndroid Build Coastguard Worker 
317*03ce13f7SAndroid Build Coastguard Worker 					slice += slicePitchBytes;
318*03ce13f7SAndroid Build Coastguard Worker 				}
319*03ce13f7SAndroid Build Coastguard Worker 			}
320*03ce13f7SAndroid Build Coastguard Worker 		}
321*03ce13f7SAndroid Build Coastguard Worker 	}
322*03ce13f7SAndroid Build Coastguard Worker 	dest->contentsChanged(subresourceRange);
323*03ce13f7SAndroid Build Coastguard Worker 
324*03ce13f7SAndroid Build Coastguard Worker 	return true;
325*03ce13f7SAndroid Build Coastguard Worker }
326*03ce13f7SAndroid Build Coastguard Worker 
readFloat4(Pointer<Byte> element,const State & state)327*03ce13f7SAndroid Build Coastguard Worker Float4 Blitter::readFloat4(Pointer<Byte> element, const State &state)
328*03ce13f7SAndroid Build Coastguard Worker {
329*03ce13f7SAndroid Build Coastguard Worker 	Float4 c(0.0f, 0.0f, 0.0f, 1.0f);
330*03ce13f7SAndroid Build Coastguard Worker 
331*03ce13f7SAndroid Build Coastguard Worker 	switch(state.sourceFormat)
332*03ce13f7SAndroid Build Coastguard Worker 	{
333*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
334*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int(*Pointer<Byte>(element)) & Int(0xF));
335*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float((Int(*Pointer<Byte>(element)) >> 4) & Int(0xF));
336*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int(*Pointer<Byte>(element + 1)) & Int(0xF));
337*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float((Int(*Pointer<Byte>(element + 1)) >> 4) & Int(0xF));
338*03ce13f7SAndroid Build Coastguard Worker 		break;
339*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SINT:
340*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SNORM:
341*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<SByte>(element)));
342*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0x7F);
343*03ce13f7SAndroid Build Coastguard Worker 		break;
344*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UNORM:
345*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UINT:
346*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SRGB:
347*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<Byte>(element)));
348*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0xFF);
349*03ce13f7SAndroid Build Coastguard Worker 		break;
350*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SINT:
351*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SNORM:
352*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<Short>(element)));
353*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0x7FFF);
354*03ce13f7SAndroid Build Coastguard Worker 		break;
355*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UNORM:
356*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UINT:
357*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<UShort>(element)));
358*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0xFFFF);
359*03ce13f7SAndroid Build Coastguard Worker 		break;
360*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SINT:
361*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(*Pointer<Int>(element));
362*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0x7FFFFFFF);
363*03ce13f7SAndroid Build Coastguard Worker 		break;
364*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_UINT:
365*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(*Pointer<UInt>(element));
366*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0xFFFFFFFF);
367*03ce13f7SAndroid Build Coastguard Worker 		break;
368*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_SRGB:
369*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_UNORM:
370*03ce13f7SAndroid Build Coastguard Worker 		c = Float4(*Pointer<Byte4>(element)).zyxw;
371*03ce13f7SAndroid Build Coastguard Worker 		break;
372*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
373*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SINT:
374*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
375*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SNORM:
376*03ce13f7SAndroid Build Coastguard Worker 		c = Float4(*Pointer<SByte4>(element));
377*03ce13f7SAndroid Build Coastguard Worker 		break;
378*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
379*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
380*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UNORM:
381*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UINT:
382*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
383*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SRGB:
384*03ce13f7SAndroid Build Coastguard Worker 		c = Float4(*Pointer<Byte4>(element));
385*03ce13f7SAndroid Build Coastguard Worker 		break;
386*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SINT:
387*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SNORM:
388*03ce13f7SAndroid Build Coastguard Worker 		c = Float4(*Pointer<Short4>(element));
389*03ce13f7SAndroid Build Coastguard Worker 		break;
390*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UNORM:
391*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UINT:
392*03ce13f7SAndroid Build Coastguard Worker 		c = Float4(*Pointer<UShort4>(element));
393*03ce13f7SAndroid Build Coastguard Worker 		break;
394*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SINT:
395*03ce13f7SAndroid Build Coastguard Worker 		c = Float4(*Pointer<Int4>(element));
396*03ce13f7SAndroid Build Coastguard Worker 		break;
397*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_UINT:
398*03ce13f7SAndroid Build Coastguard Worker 		c = Float4(*Pointer<UInt4>(element));
399*03ce13f7SAndroid Build Coastguard Worker 		break;
400*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SINT:
401*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SNORM:
402*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<SByte>(element + 0)));
403*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int(*Pointer<SByte>(element + 1)));
404*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0x7F);
405*03ce13f7SAndroid Build Coastguard Worker 		break;
406*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UNORM:
407*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UINT:
408*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SRGB:
409*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<Byte>(element + 0)));
410*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int(*Pointer<Byte>(element + 1)));
411*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0xFF);
412*03ce13f7SAndroid Build Coastguard Worker 		break;
413*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SINT:
414*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SNORM:
415*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<Short>(element + 0)));
416*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int(*Pointer<Short>(element + 2)));
417*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0x7FFF);
418*03ce13f7SAndroid Build Coastguard Worker 		break;
419*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UNORM:
420*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UINT:
421*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<UShort>(element + 0)));
422*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int(*Pointer<UShort>(element + 2)));
423*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0xFFFF);
424*03ce13f7SAndroid Build Coastguard Worker 		break;
425*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SINT:
426*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(*Pointer<Int>(element + 0));
427*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(*Pointer<Int>(element + 4));
428*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0x7FFFFFFF);
429*03ce13f7SAndroid Build Coastguard Worker 		break;
430*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_UINT:
431*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(*Pointer<UInt>(element + 0));
432*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(*Pointer<UInt>(element + 4));
433*03ce13f7SAndroid Build Coastguard Worker 		c.w = float(0xFFFFFFFF);
434*03ce13f7SAndroid Build Coastguard Worker 		break;
435*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SFLOAT:
436*03ce13f7SAndroid Build Coastguard Worker 		c = *Pointer<Float4>(element);
437*03ce13f7SAndroid Build Coastguard Worker 		break;
438*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SFLOAT:
439*03ce13f7SAndroid Build Coastguard Worker 		c.x = *Pointer<Float>(element + 0);
440*03ce13f7SAndroid Build Coastguard Worker 		c.y = *Pointer<Float>(element + 4);
441*03ce13f7SAndroid Build Coastguard Worker 		break;
442*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SFLOAT:
443*03ce13f7SAndroid Build Coastguard Worker 		c.x = *Pointer<Float>(element);
444*03ce13f7SAndroid Build Coastguard Worker 		break;
445*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SFLOAT:
446*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(*Pointer<Half>(element + 6));
447*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SFLOAT:
448*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(*Pointer<Half>(element + 4));
449*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SFLOAT:
450*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(*Pointer<Half>(element + 2));
451*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SFLOAT:
452*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(*Pointer<Half>(element));
453*03ce13f7SAndroid Build Coastguard Worker 		break;
454*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
455*03ce13f7SAndroid Build Coastguard Worker 		c = r11g11b10Unpack(*Pointer<UInt>(element));
456*03ce13f7SAndroid Build Coastguard Worker 		break;
457*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
458*03ce13f7SAndroid Build Coastguard Worker 		// This type contains a common 5 bit exponent (E) and a 9 bit the mantissa for R, G and B.
459*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(*Pointer<UInt>(element) & UInt(0x000001FF));          // R's mantissa (bits 0-8)
460*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float((*Pointer<UInt>(element) & UInt(0x0003FE00)) >> 9);   // G's mantissa (bits 9-17)
461*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float((*Pointer<UInt>(element) & UInt(0x07FC0000)) >> 18);  // B's mantissa (bits 18-26)
462*03ce13f7SAndroid Build Coastguard Worker 		c *= Float4(
463*03ce13f7SAndroid Build Coastguard Worker 		    // 2^E, using the exponent (bits 27-31) and treating it as an unsigned integer value
464*03ce13f7SAndroid Build Coastguard Worker 		    Float(UInt(1) << ((*Pointer<UInt>(element) & UInt(0xF8000000)) >> 27)) *
465*03ce13f7SAndroid Build Coastguard Worker 		    // Since the 9 bit mantissa values currently stored in RGB were converted straight
466*03ce13f7SAndroid Build Coastguard Worker 		    // from int to float (in the [0, 1<<9] range instead of the [0, 1] range), they
467*03ce13f7SAndroid Build Coastguard Worker 		    // are (1 << 9) times too high.
468*03ce13f7SAndroid Build Coastguard Worker 		    // Also, the exponent has 5 bits and we compute the exponent bias of floating point
469*03ce13f7SAndroid Build Coastguard Worker 		    // formats using "2^(k-1) - 1", so, in this case, the exponent bias is 2^(5-1)-1 = 15
470*03ce13f7SAndroid Build Coastguard Worker 		    // Exponent bias (15) + number of mantissa bits per component (9) = 24
471*03ce13f7SAndroid Build Coastguard Worker 		    Float(1.0f / (1 << 24)));
472*03ce13f7SAndroid Build Coastguard Worker 		c.w = 1.0f;
473*03ce13f7SAndroid Build Coastguard Worker 		break;
474*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
475*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF000)) >> UShort(12)));
476*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x0F00)) >> UShort(8)));
477*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int((*Pointer<UShort>(element) & UShort(0x00F0)) >> UShort(4)));
478*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int(*Pointer<UShort>(element) & UShort(0x000F)));
479*03ce13f7SAndroid Build Coastguard Worker 		break;
480*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
481*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int((*Pointer<UShort>(element) & UShort(0xF000)) >> UShort(12)));
482*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int((*Pointer<UShort>(element) & UShort(0x0F00)) >> UShort(8)));
483*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x00F0)) >> UShort(4)));
484*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<UShort>(element) & UShort(0x000F)));
485*03ce13f7SAndroid Build Coastguard Worker 		break;
486*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
487*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int((*Pointer<UShort>(element) & UShort(0xF000)) >> UShort(12)));
488*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UShort>(element) & UShort(0x0F00)) >> UShort(8)));
489*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x00F0)) >> UShort(4)));
490*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x000F)));
491*03ce13f7SAndroid Build Coastguard Worker 		break;
492*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R5G6B5_UNORM_PACK16:
493*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
494*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07E0)) >> UShort(5)));
495*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
496*03ce13f7SAndroid Build Coastguard Worker 		break;
497*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B5G6R5_UNORM_PACK16:
498*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
499*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07E0)) >> UShort(5)));
500*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
501*03ce13f7SAndroid Build Coastguard Worker 		break;
502*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
503*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
504*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07C0)) >> UShort(6)));
505*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int((*Pointer<UShort>(element) & UShort(0x003E)) >> UShort(1)));
506*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int(*Pointer<UShort>(element) & UShort(0x0001)));
507*03ce13f7SAndroid Build Coastguard Worker 		break;
508*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
509*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
510*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07C0)) >> UShort(6)));
511*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UShort>(element) & UShort(0x003E)) >> UShort(1)));
512*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int(*Pointer<UShort>(element) & UShort(0x0001)));
513*03ce13f7SAndroid Build Coastguard Worker 		break;
514*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
515*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int((*Pointer<UShort>(element) & UShort(0x8000)) >> UShort(15)));
516*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UShort>(element) & UShort(0x7C00)) >> UShort(10)));
517*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x03E0)) >> UShort(5)));
518*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
519*03ce13f7SAndroid Build Coastguard Worker 		break;
520*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
521*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
522*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
523*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
524*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
525*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
526*03ce13f7SAndroid Build Coastguard Worker 		break;
527*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
528*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UINT_PACK32:
529*03ce13f7SAndroid Build Coastguard Worker 		c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
530*03ce13f7SAndroid Build Coastguard Worker 		c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
531*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
532*03ce13f7SAndroid Build Coastguard Worker 		c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
533*03ce13f7SAndroid Build Coastguard Worker 		break;
534*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_D16_UNORM:
535*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UShort>(element))));
536*03ce13f7SAndroid Build Coastguard Worker 		break;
537*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_X8_D24_UNORM_PACK32:
538*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int((*Pointer<UInt>(element) & UInt(0xFFFFFF00)) >> 8));
539*03ce13f7SAndroid Build Coastguard Worker 		break;
540*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_D32_SFLOAT:
541*03ce13f7SAndroid Build Coastguard Worker 		c.x = *Pointer<Float>(element);
542*03ce13f7SAndroid Build Coastguard Worker 		break;
543*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_S8_UINT:
544*03ce13f7SAndroid Build Coastguard Worker 		c.x = Float(Int(*Pointer<Byte>(element)));
545*03ce13f7SAndroid Build Coastguard Worker 		break;
546*03ce13f7SAndroid Build Coastguard Worker 	default:
547*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
548*03ce13f7SAndroid Build Coastguard Worker 	}
549*03ce13f7SAndroid Build Coastguard Worker 
550*03ce13f7SAndroid Build Coastguard Worker 	return c;
551*03ce13f7SAndroid Build Coastguard Worker }
552*03ce13f7SAndroid Build Coastguard Worker 
write(Float4 & c,Pointer<Byte> element,const State & state)553*03ce13f7SAndroid Build Coastguard Worker void Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
554*03ce13f7SAndroid Build Coastguard Worker {
555*03ce13f7SAndroid Build Coastguard Worker 	bool writeR = state.writeRed;
556*03ce13f7SAndroid Build Coastguard Worker 	bool writeG = state.writeGreen;
557*03ce13f7SAndroid Build Coastguard Worker 	bool writeB = state.writeBlue;
558*03ce13f7SAndroid Build Coastguard Worker 	bool writeA = state.writeAlpha;
559*03ce13f7SAndroid Build Coastguard Worker 	bool writeRGBA = writeR && writeG && writeB && writeA;
560*03ce13f7SAndroid Build Coastguard Worker 
561*03ce13f7SAndroid Build Coastguard Worker 	switch(state.destFormat)
562*03ce13f7SAndroid Build Coastguard Worker 	{
563*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R4G4_UNORM_PACK8:
564*03ce13f7SAndroid Build Coastguard Worker 		if(writeR | writeG)
565*03ce13f7SAndroid Build Coastguard Worker 		{
566*03ce13f7SAndroid Build Coastguard Worker 			if(!writeR)
567*03ce13f7SAndroid Build Coastguard Worker 			{
568*03ce13f7SAndroid Build Coastguard Worker 				*Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
569*03ce13f7SAndroid Build Coastguard Worker 				                          (*Pointer<Byte>(element) & Byte(0xF0));
570*03ce13f7SAndroid Build Coastguard Worker 			}
571*03ce13f7SAndroid Build Coastguard Worker 			else if(!writeG)
572*03ce13f7SAndroid Build Coastguard Worker 			{
573*03ce13f7SAndroid Build Coastguard Worker 				*Pointer<Byte>(element) = (*Pointer<Byte>(element) & Byte(0xF)) |
574*03ce13f7SAndroid Build Coastguard Worker 				                          (Byte(RoundInt(Float(c.x))) << Byte(4));
575*03ce13f7SAndroid Build Coastguard Worker 			}
576*03ce13f7SAndroid Build Coastguard Worker 			else
577*03ce13f7SAndroid Build Coastguard Worker 			{
578*03ce13f7SAndroid Build Coastguard Worker 				*Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
579*03ce13f7SAndroid Build Coastguard Worker 				                          (Byte(RoundInt(Float(c.x))) << Byte(4));
580*03ce13f7SAndroid Build Coastguard Worker 			}
581*03ce13f7SAndroid Build Coastguard Worker 		}
582*03ce13f7SAndroid Build Coastguard Worker 		break;
583*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
584*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
585*03ce13f7SAndroid Build Coastguard Worker 		{
586*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c) & Int4(0xF), { 12, 8, 4, 0 }));
587*03ce13f7SAndroid Build Coastguard Worker 		}
588*03ce13f7SAndroid Build Coastguard Worker 		else
589*03ce13f7SAndroid Build Coastguard Worker 		{
590*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeA ? 0x000F : 0x0000) |
591*03ce13f7SAndroid Build Coastguard Worker 			                      (writeB ? 0x00F0 : 0x0000) |
592*03ce13f7SAndroid Build Coastguard Worker 			                      (writeG ? 0x0F00 : 0x0000) |
593*03ce13f7SAndroid Build Coastguard Worker 			                      (writeR ? 0xF000 : 0x0000);
594*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
595*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
596*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c) & Int4(0xF), { 12, 8, 4, 0 })) & UShort(mask));
597*03ce13f7SAndroid Build Coastguard Worker 		}
598*03ce13f7SAndroid Build Coastguard Worker 		break;
599*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
600*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
601*03ce13f7SAndroid Build Coastguard Worker 		{
602*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c) & Int4(0xF), { 4, 8, 12, 0 }));
603*03ce13f7SAndroid Build Coastguard Worker 		}
604*03ce13f7SAndroid Build Coastguard Worker 		else
605*03ce13f7SAndroid Build Coastguard Worker 		{
606*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeA ? 0x000F : 0x0000) |
607*03ce13f7SAndroid Build Coastguard Worker 			                      (writeR ? 0x00F0 : 0x0000) |
608*03ce13f7SAndroid Build Coastguard Worker 			                      (writeG ? 0x0F00 : 0x0000) |
609*03ce13f7SAndroid Build Coastguard Worker 			                      (writeB ? 0xF000 : 0x0000);
610*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
611*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
612*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c) & Int4(0xF), { 4, 8, 12, 0 })) & UShort(mask));
613*03ce13f7SAndroid Build Coastguard Worker 		}
614*03ce13f7SAndroid Build Coastguard Worker 		break;
615*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
616*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
617*03ce13f7SAndroid Build Coastguard Worker 		{
618*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c) & Int4(0xF), { 8, 4, 0, 12 }));
619*03ce13f7SAndroid Build Coastguard Worker 		}
620*03ce13f7SAndroid Build Coastguard Worker 		else
621*03ce13f7SAndroid Build Coastguard Worker 		{
622*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeB ? 0x000F : 0x0000) |
623*03ce13f7SAndroid Build Coastguard Worker 			                      (writeG ? 0x00F0 : 0x0000) |
624*03ce13f7SAndroid Build Coastguard Worker 			                      (writeR ? 0x0F00 : 0x0000) |
625*03ce13f7SAndroid Build Coastguard Worker 			                      (writeA ? 0xF000 : 0x0000);
626*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
627*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
628*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c) & Int4(0xF), { 8, 4, 0, 12 })) & UShort(mask));
629*03ce13f7SAndroid Build Coastguard Worker 		}
630*03ce13f7SAndroid Build Coastguard Worker 		break;
631*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
632*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
633*03ce13f7SAndroid Build Coastguard Worker 		{
634*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c) & Int4(0xF), { 0, 4, 8, 12 }));
635*03ce13f7SAndroid Build Coastguard Worker 		}
636*03ce13f7SAndroid Build Coastguard Worker 		else
637*03ce13f7SAndroid Build Coastguard Worker 		{
638*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeR ? 0x000F : 0x0000) |
639*03ce13f7SAndroid Build Coastguard Worker 			                      (writeG ? 0x00F0 : 0x0000) |
640*03ce13f7SAndroid Build Coastguard Worker 			                      (writeB ? 0x0F00 : 0x0000) |
641*03ce13f7SAndroid Build Coastguard Worker 			                      (writeA ? 0xF000 : 0x0000);
642*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
643*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
644*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c) & Int4(0xF), { 0, 4, 8, 12 })) & UShort(mask));
645*03ce13f7SAndroid Build Coastguard Worker 		}
646*03ce13f7SAndroid Build Coastguard Worker 		break;
647*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_SRGB:
648*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_UNORM:
649*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
650*03ce13f7SAndroid Build Coastguard Worker 		{
651*03ce13f7SAndroid Build Coastguard Worker 			Short4 c0 = RoundShort4(c.zyxw);
652*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
653*03ce13f7SAndroid Build Coastguard Worker 		}
654*03ce13f7SAndroid Build Coastguard Worker 		else
655*03ce13f7SAndroid Build Coastguard Worker 		{
656*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
657*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
658*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
659*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
660*03ce13f7SAndroid Build Coastguard Worker 		}
661*03ce13f7SAndroid Build Coastguard Worker 		break;
662*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8_SNORM:
663*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<SByte>(element + 0) = SByte(RoundInt(Float(c.z))); }
664*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
665*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
666*03ce13f7SAndroid Build Coastguard Worker 		break;
667*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8_UNORM:
668*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8_SRGB:
669*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
670*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
671*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
672*03ce13f7SAndroid Build Coastguard Worker 		break;
673*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
674*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UNORM:
675*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
676*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SRGB:
677*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
678*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UINT:
679*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_USCALED:
680*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
681*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
682*03ce13f7SAndroid Build Coastguard Worker 		{
683*03ce13f7SAndroid Build Coastguard Worker 			Short4 c0 = RoundShort4(c);
684*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
685*03ce13f7SAndroid Build Coastguard Worker 		}
686*03ce13f7SAndroid Build Coastguard Worker 		else
687*03ce13f7SAndroid Build Coastguard Worker 		{
688*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
689*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
690*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
691*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
692*03ce13f7SAndroid Build Coastguard Worker 		}
693*03ce13f7SAndroid Build Coastguard Worker 		break;
694*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SFLOAT:
695*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
696*03ce13f7SAndroid Build Coastguard Worker 		{
697*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<Float4>(element) = c;
698*03ce13f7SAndroid Build Coastguard Worker 		}
699*03ce13f7SAndroid Build Coastguard Worker 		else
700*03ce13f7SAndroid Build Coastguard Worker 		{
701*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<Float>(element) = c.x; }
702*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<Float>(element + 4) = c.y; }
703*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<Float>(element + 8) = c.z; }
704*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<Float>(element + 12) = c.w; }
705*03ce13f7SAndroid Build Coastguard Worker 		}
706*03ce13f7SAndroid Build Coastguard Worker 		break;
707*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32_SFLOAT:
708*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Float>(element) = c.x; }
709*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Float>(element + 4) = c.y; }
710*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Float>(element + 8) = c.z; }
711*03ce13f7SAndroid Build Coastguard Worker 		break;
712*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SFLOAT:
713*03ce13f7SAndroid Build Coastguard Worker 		if(writeR && writeG)
714*03ce13f7SAndroid Build Coastguard Worker 		{
715*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<Float2>(element) = Float2(c);
716*03ce13f7SAndroid Build Coastguard Worker 		}
717*03ce13f7SAndroid Build Coastguard Worker 		else
718*03ce13f7SAndroid Build Coastguard Worker 		{
719*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<Float>(element) = c.x; }
720*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<Float>(element + 4) = c.y; }
721*03ce13f7SAndroid Build Coastguard Worker 		}
722*03ce13f7SAndroid Build Coastguard Worker 		break;
723*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SFLOAT:
724*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Float>(element) = c.x; }
725*03ce13f7SAndroid Build Coastguard Worker 		break;
726*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SFLOAT:
727*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<Half>(element + 6) = Half(c.w); }
728*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
729*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SFLOAT:
730*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Half>(element + 4) = Half(c.z); }
731*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
732*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SFLOAT:
733*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Half>(element + 2) = Half(c.y); }
734*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
735*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SFLOAT:
736*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Half>(element) = Half(c.x); }
737*03ce13f7SAndroid Build Coastguard Worker 		break;
738*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
739*03ce13f7SAndroid Build Coastguard Worker 		{
740*03ce13f7SAndroid Build Coastguard Worker 			UInt rgb = r11g11b10Pack(c);
741*03ce13f7SAndroid Build Coastguard Worker 
742*03ce13f7SAndroid Build Coastguard Worker 			UInt old = *Pointer<UInt>(element);
743*03ce13f7SAndroid Build Coastguard Worker 
744*03ce13f7SAndroid Build Coastguard Worker 			unsigned int mask = (writeR ? 0x000007FF : 0) |
745*03ce13f7SAndroid Build Coastguard Worker 			                    (writeG ? 0x003FF800 : 0) |
746*03ce13f7SAndroid Build Coastguard Worker 			                    (writeB ? 0xFFC00000 : 0);
747*03ce13f7SAndroid Build Coastguard Worker 
748*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = (rgb & mask) | (old & ~mask);
749*03ce13f7SAndroid Build Coastguard Worker 		}
750*03ce13f7SAndroid Build Coastguard Worker 		break;
751*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
752*03ce13f7SAndroid Build Coastguard Worker 		{
753*03ce13f7SAndroid Build Coastguard Worker 			ASSERT(writeRGBA);  // Can't sensibly write just part of this format.
754*03ce13f7SAndroid Build Coastguard Worker 
755*03ce13f7SAndroid Build Coastguard Worker 			// Vulkan 1.1.117 section 15.2.1 RGB to Shared Exponent Conversion
756*03ce13f7SAndroid Build Coastguard Worker 
757*03ce13f7SAndroid Build Coastguard Worker 			constexpr int N = 9;       // number of mantissa bits per component
758*03ce13f7SAndroid Build Coastguard Worker 			constexpr int B = 15;      // exponent bias
759*03ce13f7SAndroid Build Coastguard Worker 			constexpr int E_max = 31;  // maximum possible biased exponent value
760*03ce13f7SAndroid Build Coastguard Worker 
761*03ce13f7SAndroid Build Coastguard Worker 			// Maximum representable value.
762*03ce13f7SAndroid Build Coastguard Worker 			constexpr float sharedexp_max = ((static_cast<float>(1 << N) - 1) / static_cast<float>(1 << N)) * static_cast<float>(1 << (E_max - B));
763*03ce13f7SAndroid Build Coastguard Worker 
764*03ce13f7SAndroid Build Coastguard Worker 			// Clamp components to valid range. NaN becomes 0.
765*03ce13f7SAndroid Build Coastguard Worker 			Float red_c = Min(IfThenElse(!(c.x > 0), Float(0), Float(c.x)), sharedexp_max);
766*03ce13f7SAndroid Build Coastguard Worker 			Float green_c = Min(IfThenElse(!(c.y > 0), Float(0), Float(c.y)), sharedexp_max);
767*03ce13f7SAndroid Build Coastguard Worker 			Float blue_c = Min(IfThenElse(!(c.z > 0), Float(0), Float(c.z)), sharedexp_max);
768*03ce13f7SAndroid Build Coastguard Worker 
769*03ce13f7SAndroid Build Coastguard Worker 			// We're reducing the mantissa to 9 bits, so we must round up if the next
770*03ce13f7SAndroid Build Coastguard Worker 			// bit is 1. In other words add 0.5 to the new mantissa's position and
771*03ce13f7SAndroid Build Coastguard Worker 			// allow overflow into the exponent so we can scale correctly.
772*03ce13f7SAndroid Build Coastguard Worker 			constexpr int half = 1 << (23 - N);
773*03ce13f7SAndroid Build Coastguard Worker 			Float red_r = As<Float>(As<Int>(red_c) + half);
774*03ce13f7SAndroid Build Coastguard Worker 			Float green_r = As<Float>(As<Int>(green_c) + half);
775*03ce13f7SAndroid Build Coastguard Worker 			Float blue_r = As<Float>(As<Int>(blue_c) + half);
776*03ce13f7SAndroid Build Coastguard Worker 
777*03ce13f7SAndroid Build Coastguard Worker 			// The largest component determines the shared exponent. It can't be lower
778*03ce13f7SAndroid Build Coastguard Worker 			// than 0 (after bias subtraction) so also limit to the mimimum representable.
779*03ce13f7SAndroid Build Coastguard Worker 			constexpr float min_s = 0.5f / (1 << B);
780*03ce13f7SAndroid Build Coastguard Worker 			Float max_s = Max(Max(red_r, green_r), Max(blue_r, min_s));
781*03ce13f7SAndroid Build Coastguard Worker 
782*03ce13f7SAndroid Build Coastguard Worker 			// Obtain the reciprocal of the shared exponent by inverting the bits,
783*03ce13f7SAndroid Build Coastguard Worker 			// and scale by the new mantissa's size. Note that the IEEE-754 single-precision
784*03ce13f7SAndroid Build Coastguard Worker 			// format has an implicit leading 1, but this shared component format does not.
785*03ce13f7SAndroid Build Coastguard Worker 			Float scale = As<Float>((As<Int>(max_s) & 0x7F800000) ^ 0x7F800000) * (1 << (N - 2));
786*03ce13f7SAndroid Build Coastguard Worker 
787*03ce13f7SAndroid Build Coastguard Worker 			UInt R9 = RoundInt(red_c * scale);
788*03ce13f7SAndroid Build Coastguard Worker 			UInt G9 = UInt(RoundInt(green_c * scale));
789*03ce13f7SAndroid Build Coastguard Worker 			UInt B9 = UInt(RoundInt(blue_c * scale));
790*03ce13f7SAndroid Build Coastguard Worker 			UInt E5 = (As<UInt>(max_s) >> 23) - 127 + 15 + 1;
791*03ce13f7SAndroid Build Coastguard Worker 
792*03ce13f7SAndroid Build Coastguard Worker 			UInt E5B9G9R9 = (E5 << 27) | (B9 << 18) | (G9 << 9) | R9;
793*03ce13f7SAndroid Build Coastguard Worker 
794*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = E5B9G9R9;
795*03ce13f7SAndroid Build Coastguard Worker 		}
796*03ce13f7SAndroid Build Coastguard Worker 		break;
797*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_SNORM:
798*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.z))); }
799*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
800*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
801*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
802*03ce13f7SAndroid Build Coastguard Worker 		break;
803*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
804*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SINT:
805*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
806*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SNORM:
807*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SSCALED:
808*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
809*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
810*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
811*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_SINT:
812*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_SNORM:
813*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_SSCALED:
814*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.z))); }
815*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
816*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SINT:
817*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SNORM:
818*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SSCALED:
819*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
820*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
821*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SINT:
822*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SNORM:
823*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SSCALED:
824*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.x))); }
825*03ce13f7SAndroid Build Coastguard Worker 		break;
826*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_UINT:
827*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_UNORM:
828*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_USCALED:
829*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_SRGB:
830*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
831*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
832*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UINT:
833*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UNORM:
834*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_USCALED:
835*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SRGB:
836*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
837*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
838*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UINT:
839*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UNORM:
840*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_USCALED:
841*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SRGB:
842*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x))); }
843*03ce13f7SAndroid Build Coastguard Worker 		break;
844*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SINT:
845*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SNORM:
846*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SSCALED:
847*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
848*03ce13f7SAndroid Build Coastguard Worker 		{
849*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<Short4>(element) = Short4(RoundInt(c));
850*03ce13f7SAndroid Build Coastguard Worker 		}
851*03ce13f7SAndroid Build Coastguard Worker 		else
852*03ce13f7SAndroid Build Coastguard Worker 		{
853*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
854*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
855*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
856*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<Short>(element + 6) = Short(RoundInt(Float(c.w))); }
857*03ce13f7SAndroid Build Coastguard Worker 		}
858*03ce13f7SAndroid Build Coastguard Worker 		break;
859*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SINT:
860*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SNORM:
861*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SSCALED:
862*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
863*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
864*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
865*03ce13f7SAndroid Build Coastguard Worker 		break;
866*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SINT:
867*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SNORM:
868*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SSCALED:
869*03ce13f7SAndroid Build Coastguard Worker 		if(writeR && writeG)
870*03ce13f7SAndroid Build Coastguard Worker 		{
871*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<Short2>(element) = Short2(Short4(RoundInt(c)));
872*03ce13f7SAndroid Build Coastguard Worker 		}
873*03ce13f7SAndroid Build Coastguard Worker 		else
874*03ce13f7SAndroid Build Coastguard Worker 		{
875*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
876*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
877*03ce13f7SAndroid Build Coastguard Worker 		}
878*03ce13f7SAndroid Build Coastguard Worker 		break;
879*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SINT:
880*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SNORM:
881*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SSCALED:
882*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
883*03ce13f7SAndroid Build Coastguard Worker 		break;
884*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UINT:
885*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UNORM:
886*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_USCALED:
887*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
888*03ce13f7SAndroid Build Coastguard Worker 		{
889*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort4>(element) = UShort4(RoundInt(c));
890*03ce13f7SAndroid Build Coastguard Worker 		}
891*03ce13f7SAndroid Build Coastguard Worker 		else
892*03ce13f7SAndroid Build Coastguard Worker 		{
893*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
894*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
895*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
896*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<UShort>(element + 6) = UShort(RoundInt(Float(c.w))); }
897*03ce13f7SAndroid Build Coastguard Worker 		}
898*03ce13f7SAndroid Build Coastguard Worker 		break;
899*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_UINT:
900*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_UNORM:
901*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_USCALED:
902*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
903*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
904*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
905*03ce13f7SAndroid Build Coastguard Worker 		break;
906*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UINT:
907*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UNORM:
908*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_USCALED:
909*03ce13f7SAndroid Build Coastguard Worker 		if(writeR && writeG)
910*03ce13f7SAndroid Build Coastguard Worker 		{
911*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort2>(element) = UShort2(UShort4(RoundInt(c)));
912*03ce13f7SAndroid Build Coastguard Worker 		}
913*03ce13f7SAndroid Build Coastguard Worker 		else
914*03ce13f7SAndroid Build Coastguard Worker 		{
915*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
916*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
917*03ce13f7SAndroid Build Coastguard Worker 		}
918*03ce13f7SAndroid Build Coastguard Worker 		break;
919*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UINT:
920*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UNORM:
921*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_USCALED:
922*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
923*03ce13f7SAndroid Build Coastguard Worker 		break;
924*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SINT:
925*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
926*03ce13f7SAndroid Build Coastguard Worker 		{
927*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<Int4>(element) = RoundInt(c);
928*03ce13f7SAndroid Build Coastguard Worker 		}
929*03ce13f7SAndroid Build Coastguard Worker 		else
930*03ce13f7SAndroid Build Coastguard Worker 		{
931*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
932*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
933*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
934*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<Int>(element + 12) = RoundInt(Float(c.w)); }
935*03ce13f7SAndroid Build Coastguard Worker 		}
936*03ce13f7SAndroid Build Coastguard Worker 		break;
937*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32_SINT:
938*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
939*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
940*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SINT:
941*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
942*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
943*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SINT:
944*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
945*03ce13f7SAndroid Build Coastguard Worker 		break;
946*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_UINT:
947*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
948*03ce13f7SAndroid Build Coastguard Worker 		{
949*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt4>(element) = UInt4(RoundInt(c));
950*03ce13f7SAndroid Build Coastguard Worker 		}
951*03ce13f7SAndroid Build Coastguard Worker 		else
952*03ce13f7SAndroid Build Coastguard Worker 		{
953*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
954*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
955*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
956*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(RoundInt(Float(c.w))); }
957*03ce13f7SAndroid Build Coastguard Worker 		}
958*03ce13f7SAndroid Build Coastguard Worker 		break;
959*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32_UINT:
960*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
961*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
962*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_UINT:
963*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
964*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
965*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_UINT:
966*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
967*03ce13f7SAndroid Build Coastguard Worker 		break;
968*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R5G6B5_UNORM_PACK16:
969*03ce13f7SAndroid Build Coastguard Worker 		if(writeR && writeG && writeB)
970*03ce13f7SAndroid Build Coastguard Worker 		{
971*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c.xyzz), { 11, 5, 0, 0 }));
972*03ce13f7SAndroid Build Coastguard Worker 		}
973*03ce13f7SAndroid Build Coastguard Worker 		else
974*03ce13f7SAndroid Build Coastguard Worker 		{
975*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeB ? 0x001F : 0x0000) | (writeG ? 0x07E0 : 0x0000) | (writeR ? 0xF800 : 0x0000);
976*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
977*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
978*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c.xyzz), { 11, 5, 0, 0 })) &
979*03ce13f7SAndroid Build Coastguard Worker 			                             UShort(mask));
980*03ce13f7SAndroid Build Coastguard Worker 		}
981*03ce13f7SAndroid Build Coastguard Worker 		break;
982*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B5G6R5_UNORM_PACK16:
983*03ce13f7SAndroid Build Coastguard Worker 		if(writeR && writeG && writeB)
984*03ce13f7SAndroid Build Coastguard Worker 		{
985*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c.zyxx), { 11, 5, 0, 0 }));
986*03ce13f7SAndroid Build Coastguard Worker 		}
987*03ce13f7SAndroid Build Coastguard Worker 		else
988*03ce13f7SAndroid Build Coastguard Worker 		{
989*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeR ? 0x001F : 0x0000) | (writeG ? 0x07E0 : 0x0000) | (writeB ? 0xF800 : 0x0000);
990*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
991*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
992*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c.zyxx), { 11, 5, 0, 0 })) &
993*03ce13f7SAndroid Build Coastguard Worker 			                             UShort(mask));
994*03ce13f7SAndroid Build Coastguard Worker 		}
995*03ce13f7SAndroid Build Coastguard Worker 		break;
996*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
997*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
998*03ce13f7SAndroid Build Coastguard Worker 		{
999*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c), { 11, 6, 1, 0 }));
1000*03ce13f7SAndroid Build Coastguard Worker 		}
1001*03ce13f7SAndroid Build Coastguard Worker 		else
1002*03ce13f7SAndroid Build Coastguard Worker 		{
1003*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeA ? 0x8000 : 0x0000) |
1004*03ce13f7SAndroid Build Coastguard Worker 			                      (writeR ? 0x7C00 : 0x0000) |
1005*03ce13f7SAndroid Build Coastguard Worker 			                      (writeG ? 0x03E0 : 0x0000) |
1006*03ce13f7SAndroid Build Coastguard Worker 			                      (writeB ? 0x001F : 0x0000);
1007*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
1008*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
1009*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c), { 11, 6, 1, 0 })) &
1010*03ce13f7SAndroid Build Coastguard Worker 			                             UShort(mask));
1011*03ce13f7SAndroid Build Coastguard Worker 		}
1012*03ce13f7SAndroid Build Coastguard Worker 		break;
1013*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1014*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
1015*03ce13f7SAndroid Build Coastguard Worker 		{
1016*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c), { 1, 6, 11, 0 }));
1017*03ce13f7SAndroid Build Coastguard Worker 		}
1018*03ce13f7SAndroid Build Coastguard Worker 		else
1019*03ce13f7SAndroid Build Coastguard Worker 		{
1020*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeA ? 0x8000 : 0x0000) |
1021*03ce13f7SAndroid Build Coastguard Worker 			                      (writeR ? 0x7C00 : 0x0000) |
1022*03ce13f7SAndroid Build Coastguard Worker 			                      (writeG ? 0x03E0 : 0x0000) |
1023*03ce13f7SAndroid Build Coastguard Worker 			                      (writeB ? 0x001F : 0x0000);
1024*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
1025*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
1026*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c), { 1, 6, 11, 0 })) &
1027*03ce13f7SAndroid Build Coastguard Worker 			                             UShort(mask));
1028*03ce13f7SAndroid Build Coastguard Worker 		}
1029*03ce13f7SAndroid Build Coastguard Worker 		break;
1030*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1031*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
1032*03ce13f7SAndroid Build Coastguard Worker 		{
1033*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = UShort(PackFields(RoundInt(c), { 10, 5, 0, 15 }));
1034*03ce13f7SAndroid Build Coastguard Worker 		}
1035*03ce13f7SAndroid Build Coastguard Worker 		else
1036*03ce13f7SAndroid Build Coastguard Worker 		{
1037*03ce13f7SAndroid Build Coastguard Worker 			unsigned short mask = (writeA ? 0x8000 : 0x0000) |
1038*03ce13f7SAndroid Build Coastguard Worker 			                      (writeR ? 0x7C00 : 0x0000) |
1039*03ce13f7SAndroid Build Coastguard Worker 			                      (writeG ? 0x03E0 : 0x0000) |
1040*03ce13f7SAndroid Build Coastguard Worker 			                      (writeB ? 0x001F : 0x0000);
1041*03ce13f7SAndroid Build Coastguard Worker 			unsigned short unmask = ~mask;
1042*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
1043*03ce13f7SAndroid Build Coastguard Worker 			                            (UShort(PackFields(RoundInt(c), { 10, 5, 0, 15 })) &
1044*03ce13f7SAndroid Build Coastguard Worker 			                             UShort(mask));
1045*03ce13f7SAndroid Build Coastguard Worker 		}
1046*03ce13f7SAndroid Build Coastguard Worker 		break;
1047*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1048*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1049*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
1050*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
1051*03ce13f7SAndroid Build Coastguard Worker 		{
1052*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = As<UInt>(PackFields(RoundInt(c), { 0, 10, 20, 30 }));
1053*03ce13f7SAndroid Build Coastguard Worker 		}
1054*03ce13f7SAndroid Build Coastguard Worker 		else
1055*03ce13f7SAndroid Build Coastguard Worker 		{
1056*03ce13f7SAndroid Build Coastguard Worker 			unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1057*03ce13f7SAndroid Build Coastguard Worker 			                    (writeB ? 0x3FF00000 : 0x0000) |
1058*03ce13f7SAndroid Build Coastguard Worker 			                    (writeG ? 0x000FFC00 : 0x0000) |
1059*03ce13f7SAndroid Build Coastguard Worker 			                    (writeR ? 0x000003FF : 0x0000);
1060*03ce13f7SAndroid Build Coastguard Worker 			unsigned int unmask = ~mask;
1061*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1062*03ce13f7SAndroid Build Coastguard Worker 			                          (As<UInt>(PackFields(RoundInt(c), { 0, 10, 20, 30 })) &
1063*03ce13f7SAndroid Build Coastguard Worker 			                           UInt(mask));
1064*03ce13f7SAndroid Build Coastguard Worker 		}
1065*03ce13f7SAndroid Build Coastguard Worker 		break;
1066*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1067*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1068*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
1069*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
1070*03ce13f7SAndroid Build Coastguard Worker 		{
1071*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = As<UInt>(PackFields(RoundInt(c), { 20, 10, 0, 30 }));
1072*03ce13f7SAndroid Build Coastguard Worker 		}
1073*03ce13f7SAndroid Build Coastguard Worker 		else
1074*03ce13f7SAndroid Build Coastguard Worker 		{
1075*03ce13f7SAndroid Build Coastguard Worker 			unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1076*03ce13f7SAndroid Build Coastguard Worker 			                    (writeR ? 0x3FF00000 : 0x0000) |
1077*03ce13f7SAndroid Build Coastguard Worker 			                    (writeG ? 0x000FFC00 : 0x0000) |
1078*03ce13f7SAndroid Build Coastguard Worker 			                    (writeB ? 0x000003FF : 0x0000);
1079*03ce13f7SAndroid Build Coastguard Worker 			unsigned int unmask = ~mask;
1080*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1081*03ce13f7SAndroid Build Coastguard Worker 			                          (As<UInt>(PackFields(RoundInt(c), { 20, 10, 0, 30 })) &
1082*03ce13f7SAndroid Build Coastguard Worker 			                           UInt(mask));
1083*03ce13f7SAndroid Build Coastguard Worker 		}
1084*03ce13f7SAndroid Build Coastguard Worker 		break;
1085*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_D16_UNORM:
1086*03ce13f7SAndroid Build Coastguard Worker 		*Pointer<UShort>(element) = UShort(RoundInt(Float(c.x)));
1087*03ce13f7SAndroid Build Coastguard Worker 		break;
1088*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_X8_D24_UNORM_PACK32:
1089*03ce13f7SAndroid Build Coastguard Worker 		*Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) << 8);
1090*03ce13f7SAndroid Build Coastguard Worker 		break;
1091*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_D32_SFLOAT:
1092*03ce13f7SAndroid Build Coastguard Worker 		*Pointer<Float>(element) = c.x;
1093*03ce13f7SAndroid Build Coastguard Worker 		break;
1094*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_S8_UINT:
1095*03ce13f7SAndroid Build Coastguard Worker 		*Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
1096*03ce13f7SAndroid Build Coastguard Worker 		break;
1097*03ce13f7SAndroid Build Coastguard Worker 	default:
1098*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("Blitter destination format %d", (int)state.destFormat);
1099*03ce13f7SAndroid Build Coastguard Worker 		break;
1100*03ce13f7SAndroid Build Coastguard Worker 	}
1101*03ce13f7SAndroid Build Coastguard Worker }
1102*03ce13f7SAndroid Build Coastguard Worker 
readInt4(Pointer<Byte> element,const State & state)1103*03ce13f7SAndroid Build Coastguard Worker Int4 Blitter::readInt4(Pointer<Byte> element, const State &state)
1104*03ce13f7SAndroid Build Coastguard Worker {
1105*03ce13f7SAndroid Build Coastguard Worker 	Int4 c(0, 0, 0, 1);
1106*03ce13f7SAndroid Build Coastguard Worker 
1107*03ce13f7SAndroid Build Coastguard Worker 	switch(state.sourceFormat)
1108*03ce13f7SAndroid Build Coastguard Worker 	{
1109*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1110*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SINT:
1111*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<SByte>(element + 3)), 3);
1112*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<SByte>(element + 2)), 2);
1113*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1114*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SINT:
1115*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<SByte>(element + 1)), 1);
1116*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1117*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SINT:
1118*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<SByte>(element)), 0);
1119*03ce13f7SAndroid Build Coastguard Worker 		break;
1120*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1121*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000003FF))), 0);
1122*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10), 1);
1123*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20), 2);
1124*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30), 3);
1125*03ce13f7SAndroid Build Coastguard Worker 		break;
1126*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1127*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000003FF))), 2);
1128*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10), 1);
1129*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20), 0);
1130*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30), 3);
1131*03ce13f7SAndroid Build Coastguard Worker 		break;
1132*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1133*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UINT:
1134*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<Byte>(element + 3)), 3);
1135*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<Byte>(element + 2)), 2);
1136*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1137*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UINT:
1138*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<Byte>(element + 1)), 1);
1139*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1140*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UINT:
1141*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_S8_UINT:
1142*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<Byte>(element)), 0);
1143*03ce13f7SAndroid Build Coastguard Worker 		break;
1144*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SINT:
1145*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<Short>(element + 6)), 3);
1146*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<Short>(element + 4)), 2);
1147*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1148*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SINT:
1149*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<Short>(element + 2)), 1);
1150*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1151*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SINT:
1152*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<Short>(element)), 0);
1153*03ce13f7SAndroid Build Coastguard Worker 		break;
1154*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UINT:
1155*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<UShort>(element + 6)), 3);
1156*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<UShort>(element + 4)), 2);
1157*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1158*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UINT:
1159*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<UShort>(element + 2)), 1);
1160*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1161*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UINT:
1162*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, Int(*Pointer<UShort>(element)), 0);
1163*03ce13f7SAndroid Build Coastguard Worker 		break;
1164*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SINT:
1165*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_UINT:
1166*03ce13f7SAndroid Build Coastguard Worker 		c = *Pointer<Int4>(element);
1167*03ce13f7SAndroid Build Coastguard Worker 		break;
1168*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SINT:
1169*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_UINT:
1170*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, *Pointer<Int>(element + 4), 1);
1171*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1172*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SINT:
1173*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_UINT:
1174*03ce13f7SAndroid Build Coastguard Worker 		c = Insert(c, *Pointer<Int>(element), 0);
1175*03ce13f7SAndroid Build Coastguard Worker 		break;
1176*03ce13f7SAndroid Build Coastguard Worker 	default:
1177*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
1178*03ce13f7SAndroid Build Coastguard Worker 	}
1179*03ce13f7SAndroid Build Coastguard Worker 
1180*03ce13f7SAndroid Build Coastguard Worker 	return c;
1181*03ce13f7SAndroid Build Coastguard Worker }
1182*03ce13f7SAndroid Build Coastguard Worker 
write(Int4 & c,Pointer<Byte> element,const State & state)1183*03ce13f7SAndroid Build Coastguard Worker void Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
1184*03ce13f7SAndroid Build Coastguard Worker {
1185*03ce13f7SAndroid Build Coastguard Worker 	bool writeR = state.writeRed;
1186*03ce13f7SAndroid Build Coastguard Worker 	bool writeG = state.writeGreen;
1187*03ce13f7SAndroid Build Coastguard Worker 	bool writeB = state.writeBlue;
1188*03ce13f7SAndroid Build Coastguard Worker 	bool writeA = state.writeAlpha;
1189*03ce13f7SAndroid Build Coastguard Worker 	bool writeRGBA = writeR && writeG && writeB && writeA;
1190*03ce13f7SAndroid Build Coastguard Worker 
1191*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(state.sourceFormat.isUnsigned() == state.destFormat.isUnsigned());
1192*03ce13f7SAndroid Build Coastguard Worker 
1193*03ce13f7SAndroid Build Coastguard Worker 	switch(state.destFormat)
1194*03ce13f7SAndroid Build Coastguard Worker 	{
1195*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1196*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1197*03ce13f7SAndroid Build Coastguard Worker 		c = Min(As<UInt4>(c), UInt4(0x03FF, 0x03FF, 0x03FF, 0x0003));
1198*03ce13f7SAndroid Build Coastguard Worker 		break;
1199*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1200*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UINT:
1201*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_UINT:
1202*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UINT:
1203*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UINT:
1204*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_USCALED:
1205*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_USCALED:
1206*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_USCALED:
1207*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_USCALED:
1208*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_S8_UINT:
1209*03ce13f7SAndroid Build Coastguard Worker 		c = Min(As<UInt4>(c), UInt4(0xFF));
1210*03ce13f7SAndroid Build Coastguard Worker 		break;
1211*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UINT:
1212*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_UINT:
1213*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UINT:
1214*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UINT:
1215*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_USCALED:
1216*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_USCALED:
1217*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_USCALED:
1218*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_USCALED:
1219*03ce13f7SAndroid Build Coastguard Worker 		c = Min(As<UInt4>(c), UInt4(0xFFFF));
1220*03ce13f7SAndroid Build Coastguard Worker 		break;
1221*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1222*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SINT:
1223*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SINT:
1224*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SINT:
1225*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SSCALED:
1226*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_SSCALED:
1227*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SSCALED:
1228*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SSCALED:
1229*03ce13f7SAndroid Build Coastguard Worker 		c = Min(Max(c, Int4(-0x80)), Int4(0x7F));
1230*03ce13f7SAndroid Build Coastguard Worker 		break;
1231*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SINT:
1232*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SINT:
1233*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SINT:
1234*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SINT:
1235*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SSCALED:
1236*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SSCALED:
1237*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SSCALED:
1238*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SSCALED:
1239*03ce13f7SAndroid Build Coastguard Worker 		c = Min(Max(c, Int4(-0x8000)), Int4(0x7FFF));
1240*03ce13f7SAndroid Build Coastguard Worker 		break;
1241*03ce13f7SAndroid Build Coastguard Worker 	default:
1242*03ce13f7SAndroid Build Coastguard Worker 		break;
1243*03ce13f7SAndroid Build Coastguard Worker 	}
1244*03ce13f7SAndroid Build Coastguard Worker 
1245*03ce13f7SAndroid Build Coastguard Worker 	switch(state.destFormat)
1246*03ce13f7SAndroid Build Coastguard Worker 	{
1247*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_SINT:
1248*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_SSCALED:
1249*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
1250*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1251*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8_SINT:
1252*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8_SSCALED:
1253*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<SByte>(element) = SByte(Extract(c, 2)); }
1254*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
1255*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 0)); }
1256*03ce13f7SAndroid Build Coastguard Worker 		break;
1257*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1258*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SINT:
1259*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SSCALED:
1260*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
1261*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
1262*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1263*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_SINT:
1264*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_SSCALED:
1265*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 2)); }
1266*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1267*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SINT:
1268*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SSCALED:
1269*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
1270*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1271*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SINT:
1272*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SSCALED:
1273*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<SByte>(element) = SByte(Extract(c, 0)); }
1274*03ce13f7SAndroid Build Coastguard Worker 		break;
1275*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1276*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1277*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
1278*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
1279*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
1280*03ce13f7SAndroid Build Coastguard Worker 		{
1281*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = As<UInt>(PackFields(c, { 0, 10, 20, 30 }));
1282*03ce13f7SAndroid Build Coastguard Worker 		}
1283*03ce13f7SAndroid Build Coastguard Worker 		else
1284*03ce13f7SAndroid Build Coastguard Worker 		{
1285*03ce13f7SAndroid Build Coastguard Worker 			unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1286*03ce13f7SAndroid Build Coastguard Worker 			                    (writeB ? 0x3FF00000 : 0x0000) |
1287*03ce13f7SAndroid Build Coastguard Worker 			                    (writeG ? 0x000FFC00 : 0x0000) |
1288*03ce13f7SAndroid Build Coastguard Worker 			                    (writeR ? 0x000003FF : 0x0000);
1289*03ce13f7SAndroid Build Coastguard Worker 			unsigned int unmask = ~mask;
1290*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1291*03ce13f7SAndroid Build Coastguard Worker 			                          (As<UInt>(PackFields(c, { 0, 10, 20, 30 })) & UInt(mask));
1292*03ce13f7SAndroid Build Coastguard Worker 		}
1293*03ce13f7SAndroid Build Coastguard Worker 		break;
1294*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1295*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1296*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
1297*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
1298*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
1299*03ce13f7SAndroid Build Coastguard Worker 		{
1300*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = As<UInt>(PackFields(c, { 20, 10, 0, 30 }));
1301*03ce13f7SAndroid Build Coastguard Worker 		}
1302*03ce13f7SAndroid Build Coastguard Worker 		else
1303*03ce13f7SAndroid Build Coastguard Worker 		{
1304*03ce13f7SAndroid Build Coastguard Worker 			unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1305*03ce13f7SAndroid Build Coastguard Worker 			                    (writeR ? 0x3FF00000 : 0x0000) |
1306*03ce13f7SAndroid Build Coastguard Worker 			                    (writeG ? 0x000FFC00 : 0x0000) |
1307*03ce13f7SAndroid Build Coastguard Worker 			                    (writeB ? 0x000003FF : 0x0000);
1308*03ce13f7SAndroid Build Coastguard Worker 			unsigned int unmask = ~mask;
1309*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1310*03ce13f7SAndroid Build Coastguard Worker 			                          (As<UInt>(PackFields(c, { 20, 10, 0, 30 })) & UInt(mask));
1311*03ce13f7SAndroid Build Coastguard Worker 		}
1312*03ce13f7SAndroid Build Coastguard Worker 		break;
1313*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_UINT:
1314*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_USCALED:
1315*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
1316*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1317*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8_UINT:
1318*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8_USCALED:
1319*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8_SRGB:
1320*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Byte>(element) = Byte(Extract(c, 2)); }
1321*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
1322*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 0)); }
1323*03ce13f7SAndroid Build Coastguard Worker 		break;
1324*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1325*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UINT:
1326*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_USCALED:
1327*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
1328*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
1329*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1330*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_UINT:
1331*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8_USCALED:
1332*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 2)); }
1333*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1334*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UINT:
1335*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_USCALED:
1336*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
1337*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1338*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UINT:
1339*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_USCALED:
1340*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_S8_UINT:
1341*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Byte>(element) = Byte(Extract(c, 0)); }
1342*03ce13f7SAndroid Build Coastguard Worker 		break;
1343*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SINT:
1344*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SSCALED:
1345*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<Short>(element + 6) = Short(Extract(c, 3)); }
1346*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1347*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SINT:
1348*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_SSCALED:
1349*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Short>(element + 4) = Short(Extract(c, 2)); }
1350*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1351*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SINT:
1352*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SSCALED:
1353*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Short>(element + 2) = Short(Extract(c, 1)); }
1354*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1355*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SINT:
1356*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SSCALED:
1357*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Short>(element) = Short(Extract(c, 0)); }
1358*03ce13f7SAndroid Build Coastguard Worker 		break;
1359*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UINT:
1360*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_USCALED:
1361*03ce13f7SAndroid Build Coastguard Worker 		if(writeA) { *Pointer<UShort>(element + 6) = UShort(Extract(c, 3)); }
1362*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1363*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_UINT:
1364*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16_USCALED:
1365*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<UShort>(element + 4) = UShort(Extract(c, 2)); }
1366*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1367*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UINT:
1368*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_USCALED:
1369*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<UShort>(element + 2) = UShort(Extract(c, 1)); }
1370*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1371*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UINT:
1372*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_USCALED:
1373*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<UShort>(element) = UShort(Extract(c, 0)); }
1374*03ce13f7SAndroid Build Coastguard Worker 		break;
1375*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SINT:
1376*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
1377*03ce13f7SAndroid Build Coastguard Worker 		{
1378*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<Int4>(element) = c;
1379*03ce13f7SAndroid Build Coastguard Worker 		}
1380*03ce13f7SAndroid Build Coastguard Worker 		else
1381*03ce13f7SAndroid Build Coastguard Worker 		{
1382*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1383*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1384*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1385*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<Int>(element + 12) = Extract(c, 3); }
1386*03ce13f7SAndroid Build Coastguard Worker 		}
1387*03ce13f7SAndroid Build Coastguard Worker 		break;
1388*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32_SINT:
1389*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1390*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1391*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1392*03ce13f7SAndroid Build Coastguard Worker 		break;
1393*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SINT:
1394*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1395*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1396*03ce13f7SAndroid Build Coastguard Worker 		break;
1397*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SINT:
1398*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1399*03ce13f7SAndroid Build Coastguard Worker 		break;
1400*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_UINT:
1401*03ce13f7SAndroid Build Coastguard Worker 		if(writeRGBA)
1402*03ce13f7SAndroid Build Coastguard Worker 		{
1403*03ce13f7SAndroid Build Coastguard Worker 			*Pointer<UInt4>(element) = As<UInt4>(c);
1404*03ce13f7SAndroid Build Coastguard Worker 		}
1405*03ce13f7SAndroid Build Coastguard Worker 		else
1406*03ce13f7SAndroid Build Coastguard Worker 		{
1407*03ce13f7SAndroid Build Coastguard Worker 			if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1408*03ce13f7SAndroid Build Coastguard Worker 			if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
1409*03ce13f7SAndroid Build Coastguard Worker 			if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
1410*03ce13f7SAndroid Build Coastguard Worker 			if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(Extract(c, 3)); }
1411*03ce13f7SAndroid Build Coastguard Worker 		}
1412*03ce13f7SAndroid Build Coastguard Worker 		break;
1413*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32_UINT:
1414*03ce13f7SAndroid Build Coastguard Worker 		if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
1415*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1416*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_UINT:
1417*03ce13f7SAndroid Build Coastguard Worker 		if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
1418*03ce13f7SAndroid Build Coastguard Worker 		// [[fallthrough]]
1419*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_UINT:
1420*03ce13f7SAndroid Build Coastguard Worker 		if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1421*03ce13f7SAndroid Build Coastguard Worker 		break;
1422*03ce13f7SAndroid Build Coastguard Worker 	default:
1423*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("Blitter destination format %d", (int)state.destFormat);
1424*03ce13f7SAndroid Build Coastguard Worker 	}
1425*03ce13f7SAndroid Build Coastguard Worker }
1426*03ce13f7SAndroid Build Coastguard Worker 
ApplyScaleAndClamp(Float4 & value,const State & state,bool preScaled)1427*03ce13f7SAndroid Build Coastguard Worker void Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
1428*03ce13f7SAndroid Build Coastguard Worker {
1429*03ce13f7SAndroid Build Coastguard Worker 	float4 scale{}, unscale{};
1430*03ce13f7SAndroid Build Coastguard Worker 
1431*03ce13f7SAndroid Build Coastguard Worker 	if(state.clearOperation &&
1432*03ce13f7SAndroid Build Coastguard Worker 	   state.sourceFormat.isUnnormalizedInteger() &&
1433*03ce13f7SAndroid Build Coastguard Worker 	   !state.destFormat.isUnnormalizedInteger())
1434*03ce13f7SAndroid Build Coastguard Worker 	{
1435*03ce13f7SAndroid Build Coastguard Worker 		// If we're clearing a buffer from an int or uint color into a normalized color,
1436*03ce13f7SAndroid Build Coastguard Worker 		// then the whole range of the int or uint color must be scaled between 0 and 1.
1437*03ce13f7SAndroid Build Coastguard Worker 		switch(state.sourceFormat)
1438*03ce13f7SAndroid Build Coastguard Worker 		{
1439*03ce13f7SAndroid Build Coastguard Worker 		case VK_FORMAT_R32G32B32A32_SINT:
1440*03ce13f7SAndroid Build Coastguard Worker 			unscale = float4(static_cast<float>(0x7FFFFFFF));
1441*03ce13f7SAndroid Build Coastguard Worker 			break;
1442*03ce13f7SAndroid Build Coastguard Worker 		case VK_FORMAT_R32G32B32A32_UINT:
1443*03ce13f7SAndroid Build Coastguard Worker 			unscale = float4(static_cast<float>(0xFFFFFFFF));
1444*03ce13f7SAndroid Build Coastguard Worker 			break;
1445*03ce13f7SAndroid Build Coastguard Worker 		default:
1446*03ce13f7SAndroid Build Coastguard Worker 			UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
1447*03ce13f7SAndroid Build Coastguard Worker 		}
1448*03ce13f7SAndroid Build Coastguard Worker 	}
1449*03ce13f7SAndroid Build Coastguard Worker 	else
1450*03ce13f7SAndroid Build Coastguard Worker 	{
1451*03ce13f7SAndroid Build Coastguard Worker 		unscale = state.sourceFormat.getScale();
1452*03ce13f7SAndroid Build Coastguard Worker 	}
1453*03ce13f7SAndroid Build Coastguard Worker 
1454*03ce13f7SAndroid Build Coastguard Worker 	scale = state.destFormat.getScale();
1455*03ce13f7SAndroid Build Coastguard Worker 
1456*03ce13f7SAndroid Build Coastguard Worker 	bool srcSRGB = state.sourceFormat.isSRGBformat();
1457*03ce13f7SAndroid Build Coastguard Worker 	bool dstSRGB = state.destFormat.isSRGBformat();
1458*03ce13f7SAndroid Build Coastguard Worker 
1459*03ce13f7SAndroid Build Coastguard Worker 	if(state.allowSRGBConversion && ((srcSRGB && !preScaled) || dstSRGB))  // One of the formats is sRGB encoded.
1460*03ce13f7SAndroid Build Coastguard Worker 	{
1461*03ce13f7SAndroid Build Coastguard Worker 		value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) :  // Unapply scale
1462*03ce13f7SAndroid Build Coastguard Worker 		             Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w);   // Apply unscale
1463*03ce13f7SAndroid Build Coastguard Worker 		value.xyz = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : linearToSRGB(value);
1464*03ce13f7SAndroid Build Coastguard Worker 		value *= Float4(scale.x, scale.y, scale.z, scale.w);  // Apply scale
1465*03ce13f7SAndroid Build Coastguard Worker 	}
1466*03ce13f7SAndroid Build Coastguard Worker 	else if(unscale != scale)
1467*03ce13f7SAndroid Build Coastguard Worker 	{
1468*03ce13f7SAndroid Build Coastguard Worker 		value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
1469*03ce13f7SAndroid Build Coastguard Worker 	}
1470*03ce13f7SAndroid Build Coastguard Worker 
1471*03ce13f7SAndroid Build Coastguard Worker 	if(state.sourceFormat.isFloatFormat() && !state.destFormat.isFloatFormat())
1472*03ce13f7SAndroid Build Coastguard Worker 	{
1473*03ce13f7SAndroid Build Coastguard Worker 		value = Min(value, Float4(scale.x, scale.y, scale.z, scale.w));
1474*03ce13f7SAndroid Build Coastguard Worker 
1475*03ce13f7SAndroid Build Coastguard Worker 		value = Max(value, Float4(state.destFormat.isUnsignedComponent(0) ? 0.0f : -scale.x,
1476*03ce13f7SAndroid Build Coastguard Worker 		                          state.destFormat.isUnsignedComponent(1) ? 0.0f : -scale.y,
1477*03ce13f7SAndroid Build Coastguard Worker 		                          state.destFormat.isUnsignedComponent(2) ? 0.0f : -scale.z,
1478*03ce13f7SAndroid Build Coastguard Worker 		                          state.destFormat.isUnsignedComponent(3) ? 0.0f : -scale.w));
1479*03ce13f7SAndroid Build Coastguard Worker 	}
1480*03ce13f7SAndroid Build Coastguard Worker 
1481*03ce13f7SAndroid Build Coastguard Worker 	if(!state.sourceFormat.isUnsigned() && state.destFormat.isUnsigned())
1482*03ce13f7SAndroid Build Coastguard Worker 	{
1483*03ce13f7SAndroid Build Coastguard Worker 		value = Max(value, Float4(0.0f));
1484*03ce13f7SAndroid Build Coastguard Worker 	}
1485*03ce13f7SAndroid Build Coastguard Worker }
1486*03ce13f7SAndroid Build Coastguard Worker 
ComputeOffset(Int & x,Int & y,Int & pitchB,int bytes)1487*03ce13f7SAndroid Build Coastguard Worker Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes)
1488*03ce13f7SAndroid Build Coastguard Worker {
1489*03ce13f7SAndroid Build Coastguard Worker 	return y * pitchB + x * bytes;
1490*03ce13f7SAndroid Build Coastguard Worker }
1491*03ce13f7SAndroid Build Coastguard Worker 
ComputeOffset(Int & x,Int & y,Int & z,Int & sliceB,Int & pitchB,int bytes)1492*03ce13f7SAndroid Build Coastguard Worker Int Blitter::ComputeOffset(Int &x, Int &y, Int &z, Int &sliceB, Int &pitchB, int bytes)
1493*03ce13f7SAndroid Build Coastguard Worker {
1494*03ce13f7SAndroid Build Coastguard Worker 	return z * sliceB + y * pitchB + x * bytes;
1495*03ce13f7SAndroid Build Coastguard Worker }
1496*03ce13f7SAndroid Build Coastguard Worker 
sample(Pointer<Byte> & source,Float & x,Float & y,Float & z,Int & sWidth,Int & sHeight,Int & sDepth,Int & sSliceB,Int & sPitchB,const State & state)1497*03ce13f7SAndroid Build Coastguard Worker Float4 Blitter::sample(Pointer<Byte> &source, Float &x, Float &y, Float &z,
1498*03ce13f7SAndroid Build Coastguard Worker                        Int &sWidth, Int &sHeight, Int &sDepth,
1499*03ce13f7SAndroid Build Coastguard Worker                        Int &sSliceB, Int &sPitchB, const State &state)
1500*03ce13f7SAndroid Build Coastguard Worker {
1501*03ce13f7SAndroid Build Coastguard Worker 	bool intSrc = state.sourceFormat.isUnnormalizedInteger();
1502*03ce13f7SAndroid Build Coastguard Worker 	int srcBytes = state.sourceFormat.bytes();
1503*03ce13f7SAndroid Build Coastguard Worker 
1504*03ce13f7SAndroid Build Coastguard Worker 	Float4 color;
1505*03ce13f7SAndroid Build Coastguard Worker 
1506*03ce13f7SAndroid Build Coastguard Worker 	bool preScaled = false;
1507*03ce13f7SAndroid Build Coastguard Worker 	if(!state.filter || intSrc)
1508*03ce13f7SAndroid Build Coastguard Worker 	{
1509*03ce13f7SAndroid Build Coastguard Worker 		Int X = Int(x);
1510*03ce13f7SAndroid Build Coastguard Worker 		Int Y = Int(y);
1511*03ce13f7SAndroid Build Coastguard Worker 		Int Z = Int(z);
1512*03ce13f7SAndroid Build Coastguard Worker 
1513*03ce13f7SAndroid Build Coastguard Worker 		if(state.clampToEdge)
1514*03ce13f7SAndroid Build Coastguard Worker 		{
1515*03ce13f7SAndroid Build Coastguard Worker 			X = Clamp(X, 0, sWidth - 1);
1516*03ce13f7SAndroid Build Coastguard Worker 			Y = Clamp(Y, 0, sHeight - 1);
1517*03ce13f7SAndroid Build Coastguard Worker 			Z = Clamp(Z, 0, sDepth - 1);
1518*03ce13f7SAndroid Build Coastguard Worker 		}
1519*03ce13f7SAndroid Build Coastguard Worker 
1520*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> s = source + ComputeOffset(X, Y, Z, sSliceB, sPitchB, srcBytes);
1521*03ce13f7SAndroid Build Coastguard Worker 
1522*03ce13f7SAndroid Build Coastguard Worker 		color = readFloat4(s, state);
1523*03ce13f7SAndroid Build Coastguard Worker 
1524*03ce13f7SAndroid Build Coastguard Worker 		if(state.srcSamples > 1)  // Resolve multisampled source
1525*03ce13f7SAndroid Build Coastguard Worker 		{
1526*03ce13f7SAndroid Build Coastguard Worker 			if(state.allowSRGBConversion && state.sourceFormat.isSRGBformat())  // sRGB -> RGB
1527*03ce13f7SAndroid Build Coastguard Worker 			{
1528*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(color, state);
1529*03ce13f7SAndroid Build Coastguard Worker 				preScaled = true;
1530*03ce13f7SAndroid Build Coastguard Worker 			}
1531*03ce13f7SAndroid Build Coastguard Worker 			Float4 accum = color;
1532*03ce13f7SAndroid Build Coastguard Worker 			for(int sample = 1; sample < state.srcSamples; sample++)
1533*03ce13f7SAndroid Build Coastguard Worker 			{
1534*03ce13f7SAndroid Build Coastguard Worker 				s += sSliceB;
1535*03ce13f7SAndroid Build Coastguard Worker 				color = readFloat4(s, state);
1536*03ce13f7SAndroid Build Coastguard Worker 
1537*03ce13f7SAndroid Build Coastguard Worker 				if(state.allowSRGBConversion && state.sourceFormat.isSRGBformat())  // sRGB -> RGB
1538*03ce13f7SAndroid Build Coastguard Worker 				{
1539*03ce13f7SAndroid Build Coastguard Worker 					ApplyScaleAndClamp(color, state);
1540*03ce13f7SAndroid Build Coastguard Worker 					preScaled = true;
1541*03ce13f7SAndroid Build Coastguard Worker 				}
1542*03ce13f7SAndroid Build Coastguard Worker 				accum += color;
1543*03ce13f7SAndroid Build Coastguard Worker 			}
1544*03ce13f7SAndroid Build Coastguard Worker 			color = accum * Float4(1.0f / static_cast<float>(state.srcSamples));
1545*03ce13f7SAndroid Build Coastguard Worker 		}
1546*03ce13f7SAndroid Build Coastguard Worker 	}
1547*03ce13f7SAndroid Build Coastguard Worker 	else  // Bilinear filtering
1548*03ce13f7SAndroid Build Coastguard Worker 	{
1549*03ce13f7SAndroid Build Coastguard Worker 		Float X = x;
1550*03ce13f7SAndroid Build Coastguard Worker 		Float Y = y;
1551*03ce13f7SAndroid Build Coastguard Worker 		Float Z = z;
1552*03ce13f7SAndroid Build Coastguard Worker 
1553*03ce13f7SAndroid Build Coastguard Worker 		if(state.clampToEdge)
1554*03ce13f7SAndroid Build Coastguard Worker 		{
1555*03ce13f7SAndroid Build Coastguard Worker 			X = Min(Max(x, 0.5f), Float(sWidth) - 0.5f);
1556*03ce13f7SAndroid Build Coastguard Worker 			Y = Min(Max(y, 0.5f), Float(sHeight) - 0.5f);
1557*03ce13f7SAndroid Build Coastguard Worker 			Z = Min(Max(z, 0.5f), Float(sDepth) - 0.5f);
1558*03ce13f7SAndroid Build Coastguard Worker 		}
1559*03ce13f7SAndroid Build Coastguard Worker 
1560*03ce13f7SAndroid Build Coastguard Worker 		Float x0 = X - 0.5f;
1561*03ce13f7SAndroid Build Coastguard Worker 		Float y0 = Y - 0.5f;
1562*03ce13f7SAndroid Build Coastguard Worker 		Float z0 = Z - 0.5f;
1563*03ce13f7SAndroid Build Coastguard Worker 
1564*03ce13f7SAndroid Build Coastguard Worker 		Int X0 = Max(Int(x0), 0);
1565*03ce13f7SAndroid Build Coastguard Worker 		Int Y0 = Max(Int(y0), 0);
1566*03ce13f7SAndroid Build Coastguard Worker 		Int Z0 = Max(Int(z0), 0);
1567*03ce13f7SAndroid Build Coastguard Worker 
1568*03ce13f7SAndroid Build Coastguard Worker 		Int X1 = X0 + 1;
1569*03ce13f7SAndroid Build Coastguard Worker 		Int Y1 = Y0 + 1;
1570*03ce13f7SAndroid Build Coastguard Worker 		X1 = IfThenElse(X1 >= sWidth, X0, X1);
1571*03ce13f7SAndroid Build Coastguard Worker 		Y1 = IfThenElse(Y1 >= sHeight, Y0, Y1);
1572*03ce13f7SAndroid Build Coastguard Worker 
1573*03ce13f7SAndroid Build Coastguard Worker 		if(state.filter3D)
1574*03ce13f7SAndroid Build Coastguard Worker 		{
1575*03ce13f7SAndroid Build Coastguard Worker 			Int Z1 = Z0 + 1;
1576*03ce13f7SAndroid Build Coastguard Worker 			Z1 = IfThenElse(Z1 >= sHeight, Z0, Z1);
1577*03ce13f7SAndroid Build Coastguard Worker 
1578*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s000 = source + ComputeOffset(X0, Y0, Z0, sSliceB, sPitchB, srcBytes);
1579*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s010 = source + ComputeOffset(X1, Y0, Z0, sSliceB, sPitchB, srcBytes);
1580*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s100 = source + ComputeOffset(X0, Y1, Z0, sSliceB, sPitchB, srcBytes);
1581*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s110 = source + ComputeOffset(X1, Y1, Z0, sSliceB, sPitchB, srcBytes);
1582*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s001 = source + ComputeOffset(X0, Y0, Z1, sSliceB, sPitchB, srcBytes);
1583*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s011 = source + ComputeOffset(X1, Y0, Z1, sSliceB, sPitchB, srcBytes);
1584*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s101 = source + ComputeOffset(X0, Y1, Z1, sSliceB, sPitchB, srcBytes);
1585*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s111 = source + ComputeOffset(X1, Y1, Z1, sSliceB, sPitchB, srcBytes);
1586*03ce13f7SAndroid Build Coastguard Worker 
1587*03ce13f7SAndroid Build Coastguard Worker 			Float4 c000 = readFloat4(s000, state);
1588*03ce13f7SAndroid Build Coastguard Worker 			Float4 c010 = readFloat4(s010, state);
1589*03ce13f7SAndroid Build Coastguard Worker 			Float4 c100 = readFloat4(s100, state);
1590*03ce13f7SAndroid Build Coastguard Worker 			Float4 c110 = readFloat4(s110, state);
1591*03ce13f7SAndroid Build Coastguard Worker 			Float4 c001 = readFloat4(s001, state);
1592*03ce13f7SAndroid Build Coastguard Worker 			Float4 c011 = readFloat4(s011, state);
1593*03ce13f7SAndroid Build Coastguard Worker 			Float4 c101 = readFloat4(s101, state);
1594*03ce13f7SAndroid Build Coastguard Worker 			Float4 c111 = readFloat4(s111, state);
1595*03ce13f7SAndroid Build Coastguard Worker 
1596*03ce13f7SAndroid Build Coastguard Worker 			if(state.allowSRGBConversion && state.sourceFormat.isSRGBformat())  // sRGB -> RGB
1597*03ce13f7SAndroid Build Coastguard Worker 			{
1598*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c000, state);
1599*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c010, state);
1600*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c100, state);
1601*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c110, state);
1602*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c001, state);
1603*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c011, state);
1604*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c101, state);
1605*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c111, state);
1606*03ce13f7SAndroid Build Coastguard Worker 				preScaled = true;
1607*03ce13f7SAndroid Build Coastguard Worker 			}
1608*03ce13f7SAndroid Build Coastguard Worker 
1609*03ce13f7SAndroid Build Coastguard Worker 			Float4 fx = Float4(x0 - Float(X0));
1610*03ce13f7SAndroid Build Coastguard Worker 			Float4 fy = Float4(y0 - Float(Y0));
1611*03ce13f7SAndroid Build Coastguard Worker 			Float4 fz = Float4(z0 - Float(Z0));
1612*03ce13f7SAndroid Build Coastguard Worker 			Float4 ix = Float4(1.0f) - fx;
1613*03ce13f7SAndroid Build Coastguard Worker 			Float4 iy = Float4(1.0f) - fy;
1614*03ce13f7SAndroid Build Coastguard Worker 			Float4 iz = Float4(1.0f) - fz;
1615*03ce13f7SAndroid Build Coastguard Worker 
1616*03ce13f7SAndroid Build Coastguard Worker 			color = ((c000 * ix + c010 * fx) * iy +
1617*03ce13f7SAndroid Build Coastguard Worker 			         (c100 * ix + c110 * fx) * fy) *
1618*03ce13f7SAndroid Build Coastguard Worker 			            iz +
1619*03ce13f7SAndroid Build Coastguard Worker 			        ((c001 * ix + c011 * fx) * iy +
1620*03ce13f7SAndroid Build Coastguard Worker 			         (c101 * ix + c111 * fx) * fy) *
1621*03ce13f7SAndroid Build Coastguard Worker 			            fz;
1622*03ce13f7SAndroid Build Coastguard Worker 		}
1623*03ce13f7SAndroid Build Coastguard Worker 		else
1624*03ce13f7SAndroid Build Coastguard Worker 		{
1625*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s00 = source + ComputeOffset(X0, Y0, Z0, sSliceB, sPitchB, srcBytes);
1626*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s01 = source + ComputeOffset(X1, Y0, Z0, sSliceB, sPitchB, srcBytes);
1627*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, Z0, sSliceB, sPitchB, srcBytes);
1628*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, Z0, sSliceB, sPitchB, srcBytes);
1629*03ce13f7SAndroid Build Coastguard Worker 
1630*03ce13f7SAndroid Build Coastguard Worker 			Float4 c00 = readFloat4(s00, state);
1631*03ce13f7SAndroid Build Coastguard Worker 			Float4 c01 = readFloat4(s01, state);
1632*03ce13f7SAndroid Build Coastguard Worker 			Float4 c10 = readFloat4(s10, state);
1633*03ce13f7SAndroid Build Coastguard Worker 			Float4 c11 = readFloat4(s11, state);
1634*03ce13f7SAndroid Build Coastguard Worker 
1635*03ce13f7SAndroid Build Coastguard Worker 			if(state.allowSRGBConversion && state.sourceFormat.isSRGBformat())  // sRGB -> RGB
1636*03ce13f7SAndroid Build Coastguard Worker 			{
1637*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c00, state);
1638*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c01, state);
1639*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c10, state);
1640*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(c11, state);
1641*03ce13f7SAndroid Build Coastguard Worker 				preScaled = true;
1642*03ce13f7SAndroid Build Coastguard Worker 			}
1643*03ce13f7SAndroid Build Coastguard Worker 
1644*03ce13f7SAndroid Build Coastguard Worker 			Float4 fx = Float4(x0 - Float(X0));
1645*03ce13f7SAndroid Build Coastguard Worker 			Float4 fy = Float4(y0 - Float(Y0));
1646*03ce13f7SAndroid Build Coastguard Worker 			Float4 ix = Float4(1.0f) - fx;
1647*03ce13f7SAndroid Build Coastguard Worker 			Float4 iy = Float4(1.0f) - fy;
1648*03ce13f7SAndroid Build Coastguard Worker 
1649*03ce13f7SAndroid Build Coastguard Worker 			color = (c00 * ix + c01 * fx) * iy +
1650*03ce13f7SAndroid Build Coastguard Worker 			        (c10 * ix + c11 * fx) * fy;
1651*03ce13f7SAndroid Build Coastguard Worker 		}
1652*03ce13f7SAndroid Build Coastguard Worker 	}
1653*03ce13f7SAndroid Build Coastguard Worker 
1654*03ce13f7SAndroid Build Coastguard Worker 	ApplyScaleAndClamp(color, state, preScaled);
1655*03ce13f7SAndroid Build Coastguard Worker 
1656*03ce13f7SAndroid Build Coastguard Worker 	return color;
1657*03ce13f7SAndroid Build Coastguard Worker }
1658*03ce13f7SAndroid Build Coastguard Worker 
generate(const State & state)1659*03ce13f7SAndroid Build Coastguard Worker Blitter::BlitRoutineType Blitter::generate(const State &state)
1660*03ce13f7SAndroid Build Coastguard Worker {
1661*03ce13f7SAndroid Build Coastguard Worker 	BlitFunction function;
1662*03ce13f7SAndroid Build Coastguard Worker 	{
1663*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> blit(function.Arg<0>());
1664*03ce13f7SAndroid Build Coastguard Worker 
1665*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> source = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData, source));
1666*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> dest = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData, dest));
1667*03ce13f7SAndroid Build Coastguard Worker 		Int sPitchB = *Pointer<Int>(blit + OFFSET(BlitData, sPitchB));
1668*03ce13f7SAndroid Build Coastguard Worker 		Int dPitchB = *Pointer<Int>(blit + OFFSET(BlitData, dPitchB));
1669*03ce13f7SAndroid Build Coastguard Worker 		Int sSliceB = *Pointer<Int>(blit + OFFSET(BlitData, sSliceB));
1670*03ce13f7SAndroid Build Coastguard Worker 		Int dSliceB = *Pointer<Int>(blit + OFFSET(BlitData, dSliceB));
1671*03ce13f7SAndroid Build Coastguard Worker 
1672*03ce13f7SAndroid Build Coastguard Worker 		Float x0 = *Pointer<Float>(blit + OFFSET(BlitData, x0));
1673*03ce13f7SAndroid Build Coastguard Worker 		Float y0 = *Pointer<Float>(blit + OFFSET(BlitData, y0));
1674*03ce13f7SAndroid Build Coastguard Worker 		Float z0 = *Pointer<Float>(blit + OFFSET(BlitData, z0));
1675*03ce13f7SAndroid Build Coastguard Worker 		Float w = *Pointer<Float>(blit + OFFSET(BlitData, w));
1676*03ce13f7SAndroid Build Coastguard Worker 		Float h = *Pointer<Float>(blit + OFFSET(BlitData, h));
1677*03ce13f7SAndroid Build Coastguard Worker 		Float d = *Pointer<Float>(blit + OFFSET(BlitData, d));
1678*03ce13f7SAndroid Build Coastguard Worker 
1679*03ce13f7SAndroid Build Coastguard Worker 		Int x0d = *Pointer<Int>(blit + OFFSET(BlitData, x0d));
1680*03ce13f7SAndroid Build Coastguard Worker 		Int x1d = *Pointer<Int>(blit + OFFSET(BlitData, x1d));
1681*03ce13f7SAndroid Build Coastguard Worker 		Int y0d = *Pointer<Int>(blit + OFFSET(BlitData, y0d));
1682*03ce13f7SAndroid Build Coastguard Worker 		Int y1d = *Pointer<Int>(blit + OFFSET(BlitData, y1d));
1683*03ce13f7SAndroid Build Coastguard Worker 		Int z0d = *Pointer<Int>(blit + OFFSET(BlitData, z0d));
1684*03ce13f7SAndroid Build Coastguard Worker 		Int z1d = *Pointer<Int>(blit + OFFSET(BlitData, z1d));
1685*03ce13f7SAndroid Build Coastguard Worker 
1686*03ce13f7SAndroid Build Coastguard Worker 		Int sWidth = *Pointer<Int>(blit + OFFSET(BlitData, sWidth));
1687*03ce13f7SAndroid Build Coastguard Worker 		Int sHeight = *Pointer<Int>(blit + OFFSET(BlitData, sHeight));
1688*03ce13f7SAndroid Build Coastguard Worker 		Int sDepth = *Pointer<Int>(blit + OFFSET(BlitData, sDepth));
1689*03ce13f7SAndroid Build Coastguard Worker 
1690*03ce13f7SAndroid Build Coastguard Worker 		bool intSrc = state.sourceFormat.isUnnormalizedInteger();
1691*03ce13f7SAndroid Build Coastguard Worker 		bool intDst = state.destFormat.isUnnormalizedInteger();
1692*03ce13f7SAndroid Build Coastguard Worker 		bool intBoth = intSrc && intDst;
1693*03ce13f7SAndroid Build Coastguard Worker 		int srcBytes = state.sourceFormat.bytes();
1694*03ce13f7SAndroid Build Coastguard Worker 		int dstBytes = state.destFormat.bytes();
1695*03ce13f7SAndroid Build Coastguard Worker 
1696*03ce13f7SAndroid Build Coastguard Worker 		bool hasConstantColorI = false;
1697*03ce13f7SAndroid Build Coastguard Worker 		Int4 constantColorI;
1698*03ce13f7SAndroid Build Coastguard Worker 		bool hasConstantColorF = false;
1699*03ce13f7SAndroid Build Coastguard Worker 		Float4 constantColorF;
1700*03ce13f7SAndroid Build Coastguard Worker 		if(state.clearOperation)
1701*03ce13f7SAndroid Build Coastguard Worker 		{
1702*03ce13f7SAndroid Build Coastguard Worker 			if(intBoth)  // Integer types
1703*03ce13f7SAndroid Build Coastguard Worker 			{
1704*03ce13f7SAndroid Build Coastguard Worker 				constantColorI = readInt4(source, state);
1705*03ce13f7SAndroid Build Coastguard Worker 				hasConstantColorI = true;
1706*03ce13f7SAndroid Build Coastguard Worker 			}
1707*03ce13f7SAndroid Build Coastguard Worker 			else
1708*03ce13f7SAndroid Build Coastguard Worker 			{
1709*03ce13f7SAndroid Build Coastguard Worker 				constantColorF = readFloat4(source, state);
1710*03ce13f7SAndroid Build Coastguard Worker 				hasConstantColorF = true;
1711*03ce13f7SAndroid Build Coastguard Worker 
1712*03ce13f7SAndroid Build Coastguard Worker 				ApplyScaleAndClamp(constantColorF, state);
1713*03ce13f7SAndroid Build Coastguard Worker 			}
1714*03ce13f7SAndroid Build Coastguard Worker 		}
1715*03ce13f7SAndroid Build Coastguard Worker 
1716*03ce13f7SAndroid Build Coastguard Worker 		For(Int k = z0d, k < z1d, k++)
1717*03ce13f7SAndroid Build Coastguard Worker 		{
1718*03ce13f7SAndroid Build Coastguard Worker 			Float z = state.clearOperation ? RValue<Float>(z0) : z0 + Float(k) * d;
1719*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> destSlice = dest + k * dSliceB;
1720*03ce13f7SAndroid Build Coastguard Worker 
1721*03ce13f7SAndroid Build Coastguard Worker 			For(Int j = y0d, j < y1d, j++)
1722*03ce13f7SAndroid Build Coastguard Worker 			{
1723*03ce13f7SAndroid Build Coastguard Worker 				Float y = state.clearOperation ? RValue<Float>(y0) : y0 + Float(j) * h;
1724*03ce13f7SAndroid Build Coastguard Worker 				Pointer<Byte> destLine = destSlice + j * dPitchB;
1725*03ce13f7SAndroid Build Coastguard Worker 
1726*03ce13f7SAndroid Build Coastguard Worker 				For(Int i = x0d, i < x1d, i++)
1727*03ce13f7SAndroid Build Coastguard Worker 				{
1728*03ce13f7SAndroid Build Coastguard Worker 					Float x = state.clearOperation ? RValue<Float>(x0) : x0 + Float(i) * w;
1729*03ce13f7SAndroid Build Coastguard Worker 					Pointer<Byte> d = destLine + i * dstBytes;
1730*03ce13f7SAndroid Build Coastguard Worker 
1731*03ce13f7SAndroid Build Coastguard Worker 					if(hasConstantColorI)
1732*03ce13f7SAndroid Build Coastguard Worker 					{
1733*03ce13f7SAndroid Build Coastguard Worker 						for(int s = 0; s < state.destSamples; s++)
1734*03ce13f7SAndroid Build Coastguard Worker 						{
1735*03ce13f7SAndroid Build Coastguard Worker 							write(constantColorI, d, state);
1736*03ce13f7SAndroid Build Coastguard Worker 
1737*03ce13f7SAndroid Build Coastguard Worker 							d += dSliceB;
1738*03ce13f7SAndroid Build Coastguard Worker 						}
1739*03ce13f7SAndroid Build Coastguard Worker 					}
1740*03ce13f7SAndroid Build Coastguard Worker 					else if(hasConstantColorF)
1741*03ce13f7SAndroid Build Coastguard Worker 					{
1742*03ce13f7SAndroid Build Coastguard Worker 						for(int s = 0; s < state.destSamples; s++)
1743*03ce13f7SAndroid Build Coastguard Worker 						{
1744*03ce13f7SAndroid Build Coastguard Worker 							write(constantColorF, d, state);
1745*03ce13f7SAndroid Build Coastguard Worker 
1746*03ce13f7SAndroid Build Coastguard Worker 							d += dSliceB;
1747*03ce13f7SAndroid Build Coastguard Worker 						}
1748*03ce13f7SAndroid Build Coastguard Worker 					}
1749*03ce13f7SAndroid Build Coastguard Worker 					else if(intBoth)  // Integer types do not support filtering
1750*03ce13f7SAndroid Build Coastguard Worker 					{
1751*03ce13f7SAndroid Build Coastguard Worker 						Int X = Int(x);
1752*03ce13f7SAndroid Build Coastguard Worker 						Int Y = Int(y);
1753*03ce13f7SAndroid Build Coastguard Worker 						Int Z = Int(z);
1754*03ce13f7SAndroid Build Coastguard Worker 
1755*03ce13f7SAndroid Build Coastguard Worker 						if(state.clampToEdge)
1756*03ce13f7SAndroid Build Coastguard Worker 						{
1757*03ce13f7SAndroid Build Coastguard Worker 							X = Clamp(X, 0, sWidth - 1);
1758*03ce13f7SAndroid Build Coastguard Worker 							Y = Clamp(Y, 0, sHeight - 1);
1759*03ce13f7SAndroid Build Coastguard Worker 							Z = Clamp(Z, 0, sDepth - 1);
1760*03ce13f7SAndroid Build Coastguard Worker 						}
1761*03ce13f7SAndroid Build Coastguard Worker 
1762*03ce13f7SAndroid Build Coastguard Worker 						Pointer<Byte> s = source + ComputeOffset(X, Y, Z, sSliceB, sPitchB, srcBytes);
1763*03ce13f7SAndroid Build Coastguard Worker 
1764*03ce13f7SAndroid Build Coastguard Worker 						// When both formats are true integer types, we don't go to float to avoid losing precision
1765*03ce13f7SAndroid Build Coastguard Worker 						Int4 color = readInt4(s, state);
1766*03ce13f7SAndroid Build Coastguard Worker 						for(int s = 0; s < state.destSamples; s++)
1767*03ce13f7SAndroid Build Coastguard Worker 						{
1768*03ce13f7SAndroid Build Coastguard Worker 							write(color, d, state);
1769*03ce13f7SAndroid Build Coastguard Worker 
1770*03ce13f7SAndroid Build Coastguard Worker 							d += dSliceB;
1771*03ce13f7SAndroid Build Coastguard Worker 						}
1772*03ce13f7SAndroid Build Coastguard Worker 					}
1773*03ce13f7SAndroid Build Coastguard Worker 					else
1774*03ce13f7SAndroid Build Coastguard Worker 					{
1775*03ce13f7SAndroid Build Coastguard Worker 						Float4 color = sample(source, x, y, z, sWidth, sHeight, sDepth, sSliceB, sPitchB, state);
1776*03ce13f7SAndroid Build Coastguard Worker 
1777*03ce13f7SAndroid Build Coastguard Worker 						for(int s = 0; s < state.destSamples; s++)
1778*03ce13f7SAndroid Build Coastguard Worker 						{
1779*03ce13f7SAndroid Build Coastguard Worker 							write(color, d, state);
1780*03ce13f7SAndroid Build Coastguard Worker 
1781*03ce13f7SAndroid Build Coastguard Worker 							d += dSliceB;
1782*03ce13f7SAndroid Build Coastguard Worker 						}
1783*03ce13f7SAndroid Build Coastguard Worker 					}
1784*03ce13f7SAndroid Build Coastguard Worker 				}
1785*03ce13f7SAndroid Build Coastguard Worker 			}
1786*03ce13f7SAndroid Build Coastguard Worker 		}
1787*03ce13f7SAndroid Build Coastguard Worker 	}
1788*03ce13f7SAndroid Build Coastguard Worker 
1789*03ce13f7SAndroid Build Coastguard Worker 	return function("BlitRoutine");
1790*03ce13f7SAndroid Build Coastguard Worker }
1791*03ce13f7SAndroid Build Coastguard Worker 
getBlitRoutine(const State & state)1792*03ce13f7SAndroid Build Coastguard Worker Blitter::BlitRoutineType Blitter::getBlitRoutine(const State &state)
1793*03ce13f7SAndroid Build Coastguard Worker {
1794*03ce13f7SAndroid Build Coastguard Worker 	marl::lock lock(blitMutex);
1795*03ce13f7SAndroid Build Coastguard Worker 	auto blitRoutine = blitCache.lookup(state);
1796*03ce13f7SAndroid Build Coastguard Worker 
1797*03ce13f7SAndroid Build Coastguard Worker 	if(!blitRoutine)
1798*03ce13f7SAndroid Build Coastguard Worker 	{
1799*03ce13f7SAndroid Build Coastguard Worker 		blitRoutine = generate(state);
1800*03ce13f7SAndroid Build Coastguard Worker 		blitCache.add(state, blitRoutine);
1801*03ce13f7SAndroid Build Coastguard Worker 	}
1802*03ce13f7SAndroid Build Coastguard Worker 
1803*03ce13f7SAndroid Build Coastguard Worker 	return blitRoutine;
1804*03ce13f7SAndroid Build Coastguard Worker }
1805*03ce13f7SAndroid Build Coastguard Worker 
getCornerUpdateRoutine(const State & state)1806*03ce13f7SAndroid Build Coastguard Worker Blitter::CornerUpdateRoutineType Blitter::getCornerUpdateRoutine(const State &state)
1807*03ce13f7SAndroid Build Coastguard Worker {
1808*03ce13f7SAndroid Build Coastguard Worker 	marl::lock lock(cornerUpdateMutex);
1809*03ce13f7SAndroid Build Coastguard Worker 	auto cornerUpdateRoutine = cornerUpdateCache.lookup(state);
1810*03ce13f7SAndroid Build Coastguard Worker 
1811*03ce13f7SAndroid Build Coastguard Worker 	if(!cornerUpdateRoutine)
1812*03ce13f7SAndroid Build Coastguard Worker 	{
1813*03ce13f7SAndroid Build Coastguard Worker 		cornerUpdateRoutine = generateCornerUpdate(state);
1814*03ce13f7SAndroid Build Coastguard Worker 		cornerUpdateCache.add(state, cornerUpdateRoutine);
1815*03ce13f7SAndroid Build Coastguard Worker 	}
1816*03ce13f7SAndroid Build Coastguard Worker 
1817*03ce13f7SAndroid Build Coastguard Worker 	return cornerUpdateRoutine;
1818*03ce13f7SAndroid Build Coastguard Worker }
1819*03ce13f7SAndroid Build Coastguard Worker 
blit(const vk::Image * src,vk::Image * dst,VkImageBlit2KHR region,VkFilter filter)1820*03ce13f7SAndroid Build Coastguard Worker void Blitter::blit(const vk::Image *src, vk::Image *dst, VkImageBlit2KHR region, VkFilter filter)
1821*03ce13f7SAndroid Build Coastguard Worker {
1822*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(src->getFormat() != VK_FORMAT_UNDEFINED);
1823*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(dst->getFormat() != VK_FORMAT_UNDEFINED);
1824*03ce13f7SAndroid Build Coastguard Worker 
1825*03ce13f7SAndroid Build Coastguard Worker 	// Vulkan 1.2 section 18.5. Image Copies with Scaling:
1826*03ce13f7SAndroid Build Coastguard Worker 	// "The layerCount member of srcSubresource and dstSubresource must match"
1827*03ce13f7SAndroid Build Coastguard Worker 	// "The aspectMask member of srcSubresource and dstSubresource must match"
1828*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(region.srcSubresource.layerCount == region.dstSubresource.layerCount);
1829*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(region.srcSubresource.aspectMask == region.dstSubresource.aspectMask);
1830*03ce13f7SAndroid Build Coastguard Worker 
1831*03ce13f7SAndroid Build Coastguard Worker 	if(region.dstOffsets[0].x > region.dstOffsets[1].x)
1832*03ce13f7SAndroid Build Coastguard Worker 	{
1833*03ce13f7SAndroid Build Coastguard Worker 		std::swap(region.srcOffsets[0].x, region.srcOffsets[1].x);
1834*03ce13f7SAndroid Build Coastguard Worker 		std::swap(region.dstOffsets[0].x, region.dstOffsets[1].x);
1835*03ce13f7SAndroid Build Coastguard Worker 	}
1836*03ce13f7SAndroid Build Coastguard Worker 
1837*03ce13f7SAndroid Build Coastguard Worker 	if(region.dstOffsets[0].y > region.dstOffsets[1].y)
1838*03ce13f7SAndroid Build Coastguard Worker 	{
1839*03ce13f7SAndroid Build Coastguard Worker 		std::swap(region.srcOffsets[0].y, region.srcOffsets[1].y);
1840*03ce13f7SAndroid Build Coastguard Worker 		std::swap(region.dstOffsets[0].y, region.dstOffsets[1].y);
1841*03ce13f7SAndroid Build Coastguard Worker 	}
1842*03ce13f7SAndroid Build Coastguard Worker 
1843*03ce13f7SAndroid Build Coastguard Worker 	if(region.dstOffsets[0].z > region.dstOffsets[1].z)
1844*03ce13f7SAndroid Build Coastguard Worker 	{
1845*03ce13f7SAndroid Build Coastguard Worker 		std::swap(region.srcOffsets[0].z, region.srcOffsets[1].z);
1846*03ce13f7SAndroid Build Coastguard Worker 		std::swap(region.dstOffsets[0].z, region.dstOffsets[1].z);
1847*03ce13f7SAndroid Build Coastguard Worker 	}
1848*03ce13f7SAndroid Build Coastguard Worker 
1849*03ce13f7SAndroid Build Coastguard Worker 	VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask);
1850*03ce13f7SAndroid Build Coastguard Worker 	VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask);
1851*03ce13f7SAndroid Build Coastguard Worker 	VkExtent3D srcExtent = src->getMipLevelExtent(srcAspect, region.srcSubresource.mipLevel);
1852*03ce13f7SAndroid Build Coastguard Worker 
1853*03ce13f7SAndroid Build Coastguard Worker 	float widthRatio = static_cast<float>(region.srcOffsets[1].x - region.srcOffsets[0].x) /
1854*03ce13f7SAndroid Build Coastguard Worker 	                   static_cast<float>(region.dstOffsets[1].x - region.dstOffsets[0].x);
1855*03ce13f7SAndroid Build Coastguard Worker 	float heightRatio = static_cast<float>(region.srcOffsets[1].y - region.srcOffsets[0].y) /
1856*03ce13f7SAndroid Build Coastguard Worker 	                    static_cast<float>(region.dstOffsets[1].y - region.dstOffsets[0].y);
1857*03ce13f7SAndroid Build Coastguard Worker 	float depthRatio = static_cast<float>(region.srcOffsets[1].z - region.srcOffsets[0].z) /
1858*03ce13f7SAndroid Build Coastguard Worker 	                   static_cast<float>(region.dstOffsets[1].z - region.dstOffsets[0].z);
1859*03ce13f7SAndroid Build Coastguard Worker 	float x0 = region.srcOffsets[0].x + (0.5f - region.dstOffsets[0].x) * widthRatio;
1860*03ce13f7SAndroid Build Coastguard Worker 	float y0 = region.srcOffsets[0].y + (0.5f - region.dstOffsets[0].y) * heightRatio;
1861*03ce13f7SAndroid Build Coastguard Worker 	float z0 = region.srcOffsets[0].z + (0.5f - region.dstOffsets[0].z) * depthRatio;
1862*03ce13f7SAndroid Build Coastguard Worker 
1863*03ce13f7SAndroid Build Coastguard Worker 	auto srcFormat = src->getFormat(srcAspect);
1864*03ce13f7SAndroid Build Coastguard Worker 	auto dstFormat = dst->getFormat(dstAspect);
1865*03ce13f7SAndroid Build Coastguard Worker 
1866*03ce13f7SAndroid Build Coastguard Worker 	bool doFilter = (filter != VK_FILTER_NEAREST);
1867*03ce13f7SAndroid Build Coastguard Worker 	bool allowSRGBConversion =
1868*03ce13f7SAndroid Build Coastguard Worker 	    doFilter ||
1869*03ce13f7SAndroid Build Coastguard Worker 	    (src->getSampleCount() > 1) ||
1870*03ce13f7SAndroid Build Coastguard Worker 	    (srcFormat.isSRGBformat() != dstFormat.isSRGBformat());
1871*03ce13f7SAndroid Build Coastguard Worker 
1872*03ce13f7SAndroid Build Coastguard Worker 	State state(srcFormat, dstFormat, src->getSampleCount(), dst->getSampleCount(),
1873*03ce13f7SAndroid Build Coastguard Worker 	            Options{ doFilter, allowSRGBConversion });
1874*03ce13f7SAndroid Build Coastguard Worker 	state.clampToEdge = (region.srcOffsets[0].x < 0) ||
1875*03ce13f7SAndroid Build Coastguard Worker 	                    (region.srcOffsets[0].y < 0) ||
1876*03ce13f7SAndroid Build Coastguard Worker 	                    (static_cast<uint32_t>(region.srcOffsets[1].x) > srcExtent.width) ||
1877*03ce13f7SAndroid Build Coastguard Worker 	                    (static_cast<uint32_t>(region.srcOffsets[1].y) > srcExtent.height) ||
1878*03ce13f7SAndroid Build Coastguard Worker 	                    (doFilter && ((x0 < 0.5f) || (y0 < 0.5f)));
1879*03ce13f7SAndroid Build Coastguard Worker 	state.filter3D = (region.srcOffsets[1].z - region.srcOffsets[0].z) !=
1880*03ce13f7SAndroid Build Coastguard Worker 	                 (region.dstOffsets[1].z - region.dstOffsets[0].z);
1881*03ce13f7SAndroid Build Coastguard Worker 
1882*03ce13f7SAndroid Build Coastguard Worker 	auto blitRoutine = getBlitRoutine(state);
1883*03ce13f7SAndroid Build Coastguard Worker 	if(!blitRoutine)
1884*03ce13f7SAndroid Build Coastguard Worker 	{
1885*03ce13f7SAndroid Build Coastguard Worker 		return;
1886*03ce13f7SAndroid Build Coastguard Worker 	}
1887*03ce13f7SAndroid Build Coastguard Worker 
1888*03ce13f7SAndroid Build Coastguard Worker 	BlitData data = {
1889*03ce13f7SAndroid Build Coastguard Worker 		nullptr,                                                                                 // source
1890*03ce13f7SAndroid Build Coastguard Worker 		nullptr,                                                                                 // dest
1891*03ce13f7SAndroid Build Coastguard Worker 		assert_cast<uint32_t>(src->rowPitchBytes(srcAspect, region.srcSubresource.mipLevel)),    // sPitchB
1892*03ce13f7SAndroid Build Coastguard Worker 		assert_cast<uint32_t>(dst->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel)),    // dPitchB
1893*03ce13f7SAndroid Build Coastguard Worker 		assert_cast<uint32_t>(src->slicePitchBytes(srcAspect, region.srcSubresource.mipLevel)),  // sSliceB
1894*03ce13f7SAndroid Build Coastguard Worker 		assert_cast<uint32_t>(dst->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel)),  // dSliceB
1895*03ce13f7SAndroid Build Coastguard Worker 
1896*03ce13f7SAndroid Build Coastguard Worker 		x0,
1897*03ce13f7SAndroid Build Coastguard Worker 		y0,
1898*03ce13f7SAndroid Build Coastguard Worker 		z0,
1899*03ce13f7SAndroid Build Coastguard Worker 		widthRatio,
1900*03ce13f7SAndroid Build Coastguard Worker 		heightRatio,
1901*03ce13f7SAndroid Build Coastguard Worker 		depthRatio,
1902*03ce13f7SAndroid Build Coastguard Worker 
1903*03ce13f7SAndroid Build Coastguard Worker 		region.dstOffsets[0].x,  // x0d
1904*03ce13f7SAndroid Build Coastguard Worker 		region.dstOffsets[1].x,  // x1d
1905*03ce13f7SAndroid Build Coastguard Worker 		region.dstOffsets[0].y,  // y0d
1906*03ce13f7SAndroid Build Coastguard Worker 		region.dstOffsets[1].y,  // y1d
1907*03ce13f7SAndroid Build Coastguard Worker 		region.dstOffsets[0].z,  // z0d
1908*03ce13f7SAndroid Build Coastguard Worker 		region.dstOffsets[1].z,  // z1d
1909*03ce13f7SAndroid Build Coastguard Worker 
1910*03ce13f7SAndroid Build Coastguard Worker 		static_cast<int>(srcExtent.width),   // sWidth
1911*03ce13f7SAndroid Build Coastguard Worker 		static_cast<int>(srcExtent.height),  // sHeight
1912*03ce13f7SAndroid Build Coastguard Worker 		static_cast<int>(srcExtent.depth),   // sDepth
1913*03ce13f7SAndroid Build Coastguard Worker 
1914*03ce13f7SAndroid Build Coastguard Worker 		false,  // filter3D
1915*03ce13f7SAndroid Build Coastguard Worker 	};
1916*03ce13f7SAndroid Build Coastguard Worker 
1917*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource srcSubres = {
1918*03ce13f7SAndroid Build Coastguard Worker 		region.srcSubresource.aspectMask,
1919*03ce13f7SAndroid Build Coastguard Worker 		region.srcSubresource.mipLevel,
1920*03ce13f7SAndroid Build Coastguard Worker 		region.srcSubresource.baseArrayLayer
1921*03ce13f7SAndroid Build Coastguard Worker 	};
1922*03ce13f7SAndroid Build Coastguard Worker 
1923*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource dstSubres = {
1924*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.aspectMask,
1925*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.mipLevel,
1926*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.baseArrayLayer
1927*03ce13f7SAndroid Build Coastguard Worker 	};
1928*03ce13f7SAndroid Build Coastguard Worker 
1929*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresourceRange dstSubresRange = {
1930*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.aspectMask,
1931*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.mipLevel,
1932*03ce13f7SAndroid Build Coastguard Worker 		1,  // levelCount
1933*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.baseArrayLayer,
1934*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.layerCount
1935*03ce13f7SAndroid Build Coastguard Worker 	};
1936*03ce13f7SAndroid Build Coastguard Worker 
1937*03ce13f7SAndroid Build Coastguard Worker 	uint32_t lastLayer = src->getLastLayerIndex(dstSubresRange);
1938*03ce13f7SAndroid Build Coastguard Worker 
1939*03ce13f7SAndroid Build Coastguard Worker 	for(; dstSubres.arrayLayer <= lastLayer; srcSubres.arrayLayer++, dstSubres.arrayLayer++)
1940*03ce13f7SAndroid Build Coastguard Worker 	{
1941*03ce13f7SAndroid Build Coastguard Worker 		data.source = src->getTexelPointer({ 0, 0, 0 }, srcSubres);
1942*03ce13f7SAndroid Build Coastguard Worker 		data.dest = dst->getTexelPointer({ 0, 0, 0 }, dstSubres);
1943*03ce13f7SAndroid Build Coastguard Worker 
1944*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(data.source < src->end());
1945*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(data.dest < dst->end());
1946*03ce13f7SAndroid Build Coastguard Worker 
1947*03ce13f7SAndroid Build Coastguard Worker 		blitRoutine(&data);
1948*03ce13f7SAndroid Build Coastguard Worker 	}
1949*03ce13f7SAndroid Build Coastguard Worker 
1950*03ce13f7SAndroid Build Coastguard Worker 	dst->contentsChanged(dstSubresRange);
1951*03ce13f7SAndroid Build Coastguard Worker }
1952*03ce13f7SAndroid Build Coastguard Worker 
resolveDepth(const vk::ImageView * src,vk::ImageView * dst,const VkResolveModeFlagBits depthResolveMode)1953*03ce13f7SAndroid Build Coastguard Worker static void resolveDepth(const vk::ImageView *src, vk::ImageView *dst, const VkResolveModeFlagBits depthResolveMode)
1954*03ce13f7SAndroid Build Coastguard Worker {
1955*03ce13f7SAndroid Build Coastguard Worker 	if(depthResolveMode == VK_RESOLVE_MODE_NONE)
1956*03ce13f7SAndroid Build Coastguard Worker 	{
1957*03ce13f7SAndroid Build Coastguard Worker 		return;
1958*03ce13f7SAndroid Build Coastguard Worker 	}
1959*03ce13f7SAndroid Build Coastguard Worker 
1960*03ce13f7SAndroid Build Coastguard Worker 	vk::Format format = src->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT);
1961*03ce13f7SAndroid Build Coastguard Worker 	VkExtent2D extent = src->getMipLevelExtent(0, VK_IMAGE_ASPECT_DEPTH_BIT);
1962*03ce13f7SAndroid Build Coastguard Worker 	int width = extent.width;
1963*03ce13f7SAndroid Build Coastguard Worker 	int height = extent.height;
1964*03ce13f7SAndroid Build Coastguard Worker 	int pitch = src->rowPitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
1965*03ce13f7SAndroid Build Coastguard Worker 
1966*03ce13f7SAndroid Build Coastguard Worker 	// To support other resolve modes, get the slice bytes and get a pointer to each sample plane.
1967*03ce13f7SAndroid Build Coastguard Worker 	// Then modify the loop below to include logic for handling each new mode.
1968*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *source = (uint8_t *)src->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0);
1969*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *dest = (uint8_t *)dst->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0);
1970*03ce13f7SAndroid Build Coastguard Worker 
1971*03ce13f7SAndroid Build Coastguard Worker 	size_t formatSize = format.bytes();
1972*03ce13f7SAndroid Build Coastguard Worker 	// TODO(b/167558951) support other resolve modes.
1973*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(depthResolveMode == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT);
1974*03ce13f7SAndroid Build Coastguard Worker 	for(int y = 0; y < height; y++)
1975*03ce13f7SAndroid Build Coastguard Worker 	{
1976*03ce13f7SAndroid Build Coastguard Worker 		memcpy(dest, source, formatSize * width);
1977*03ce13f7SAndroid Build Coastguard Worker 
1978*03ce13f7SAndroid Build Coastguard Worker 		source += pitch;
1979*03ce13f7SAndroid Build Coastguard Worker 		dest += pitch;
1980*03ce13f7SAndroid Build Coastguard Worker 	}
1981*03ce13f7SAndroid Build Coastguard Worker 
1982*03ce13f7SAndroid Build Coastguard Worker 	dst->contentsChanged(vk::Image::DIRECT_MEMORY_ACCESS);
1983*03ce13f7SAndroid Build Coastguard Worker }
1984*03ce13f7SAndroid Build Coastguard Worker 
resolveStencil(const vk::ImageView * src,vk::ImageView * dst,const VkResolveModeFlagBits stencilResolveMode)1985*03ce13f7SAndroid Build Coastguard Worker static void resolveStencil(const vk::ImageView *src, vk::ImageView *dst, const VkResolveModeFlagBits stencilResolveMode)
1986*03ce13f7SAndroid Build Coastguard Worker {
1987*03ce13f7SAndroid Build Coastguard Worker 	if(stencilResolveMode == VK_RESOLVE_MODE_NONE)
1988*03ce13f7SAndroid Build Coastguard Worker 	{
1989*03ce13f7SAndroid Build Coastguard Worker 		return;
1990*03ce13f7SAndroid Build Coastguard Worker 	}
1991*03ce13f7SAndroid Build Coastguard Worker 
1992*03ce13f7SAndroid Build Coastguard Worker 	VkExtent2D extent = src->getMipLevelExtent(0, VK_IMAGE_ASPECT_STENCIL_BIT);
1993*03ce13f7SAndroid Build Coastguard Worker 	int width = extent.width;
1994*03ce13f7SAndroid Build Coastguard Worker 	int height = extent.height;
1995*03ce13f7SAndroid Build Coastguard Worker 	int pitch = src->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
1996*03ce13f7SAndroid Build Coastguard Worker 
1997*03ce13f7SAndroid Build Coastguard Worker 	// To support other resolve modes, use src->slicePitchBytes() and get a pointer to each sample's slice.
1998*03ce13f7SAndroid Build Coastguard Worker 	// Then modify the loop below to include logic for handling each new mode.
1999*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *source = reinterpret_cast<uint8_t *>(src->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0));
2000*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *dest = reinterpret_cast<uint8_t *>(dst->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0));
2001*03ce13f7SAndroid Build Coastguard Worker 
2002*03ce13f7SAndroid Build Coastguard Worker 	// TODO(b/167558951) support other resolve modes.
2003*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(stencilResolveMode == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT);
2004*03ce13f7SAndroid Build Coastguard Worker 	for(int y = 0; y < height; y++)
2005*03ce13f7SAndroid Build Coastguard Worker 	{
2006*03ce13f7SAndroid Build Coastguard Worker 		// Stencil is always 8 bits, so the width of the resource we're resolving is
2007*03ce13f7SAndroid Build Coastguard Worker 		// the number of bytes in each row we need to copy during for SAMPLE_ZERO
2008*03ce13f7SAndroid Build Coastguard Worker 		memcpy(dest, source, width);
2009*03ce13f7SAndroid Build Coastguard Worker 
2010*03ce13f7SAndroid Build Coastguard Worker 		source += pitch;
2011*03ce13f7SAndroid Build Coastguard Worker 		dest += pitch;
2012*03ce13f7SAndroid Build Coastguard Worker 	}
2013*03ce13f7SAndroid Build Coastguard Worker 
2014*03ce13f7SAndroid Build Coastguard Worker 	dst->contentsChanged(vk::Image::DIRECT_MEMORY_ACCESS);
2015*03ce13f7SAndroid Build Coastguard Worker }
2016*03ce13f7SAndroid Build Coastguard Worker 
resolveDepthStencil(const vk::ImageView * src,vk::ImageView * dst,VkResolveModeFlagBits depthResolveMode,VkResolveModeFlagBits stencilResolveMode)2017*03ce13f7SAndroid Build Coastguard Worker void Blitter::resolveDepthStencil(const vk::ImageView *src, vk::ImageView *dst, VkResolveModeFlagBits depthResolveMode, VkResolveModeFlagBits stencilResolveMode)
2018*03ce13f7SAndroid Build Coastguard Worker {
2019*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresourceRange srcRange = src->getSubresourceRange();
2020*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresourceRange dstRange = src->getSubresourceRange();
2021*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(src->getFormat() == dst->getFormat());
2022*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(srcRange.layerCount == 1 && dstRange.layerCount == 1);
2023*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(srcRange.aspectMask == dstRange.aspectMask);
2024*03ce13f7SAndroid Build Coastguard Worker 
2025*03ce13f7SAndroid Build Coastguard Worker 	if(srcRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
2026*03ce13f7SAndroid Build Coastguard Worker 	{
2027*03ce13f7SAndroid Build Coastguard Worker 		resolveDepth(src, dst, depthResolveMode);
2028*03ce13f7SAndroid Build Coastguard Worker 	}
2029*03ce13f7SAndroid Build Coastguard Worker 	if(srcRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
2030*03ce13f7SAndroid Build Coastguard Worker 	{
2031*03ce13f7SAndroid Build Coastguard Worker 		resolveStencil(src, dst, stencilResolveMode);
2032*03ce13f7SAndroid Build Coastguard Worker 	}
2033*03ce13f7SAndroid Build Coastguard Worker }
2034*03ce13f7SAndroid Build Coastguard Worker 
resolve(const vk::Image * src,vk::Image * dst,VkImageResolve2KHR region)2035*03ce13f7SAndroid Build Coastguard Worker void Blitter::resolve(const vk::Image *src, vk::Image *dst, VkImageResolve2KHR region)
2036*03ce13f7SAndroid Build Coastguard Worker {
2037*03ce13f7SAndroid Build Coastguard Worker 	// "The aspectMask member of srcSubresource and dstSubresource must only contain VK_IMAGE_ASPECT_COLOR_BIT"
2038*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
2039*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
2040*03ce13f7SAndroid Build Coastguard Worker 	// "The layerCount member of srcSubresource and dstSubresource must match"
2041*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(region.srcSubresource.layerCount == region.dstSubresource.layerCount);
2042*03ce13f7SAndroid Build Coastguard Worker 
2043*03ce13f7SAndroid Build Coastguard Worker 	// We use this method both for explicit resolves from vkCmdResolveImage, and implicit ones for resolve attachments.
2044*03ce13f7SAndroid Build Coastguard Worker 	// - vkCmdResolveImage: "srcImage and dstImage must have been created with the same image format."
2045*03ce13f7SAndroid Build Coastguard Worker 	// - VkSubpassDescription: "each resolve attachment that is not VK_ATTACHMENT_UNUSED must have the same VkFormat as its corresponding color attachment."
2046*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(src->getFormat() == dst->getFormat());
2047*03ce13f7SAndroid Build Coastguard Worker 
2048*03ce13f7SAndroid Build Coastguard Worker 	if(fastResolve(src, dst, region))
2049*03ce13f7SAndroid Build Coastguard Worker 	{
2050*03ce13f7SAndroid Build Coastguard Worker 		return;
2051*03ce13f7SAndroid Build Coastguard Worker 	}
2052*03ce13f7SAndroid Build Coastguard Worker 
2053*03ce13f7SAndroid Build Coastguard Worker 	// Fall back to a generic blit which performs the resolve.
2054*03ce13f7SAndroid Build Coastguard Worker 	VkImageBlit2KHR blitRegion;
2055*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR;
2056*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.pNext = nullptr;
2057*03ce13f7SAndroid Build Coastguard Worker 
2058*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.srcOffsets[0] = blitRegion.srcOffsets[1] = region.srcOffset;
2059*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.srcOffsets[1].x += region.extent.width;
2060*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.srcOffsets[1].y += region.extent.height;
2061*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.srcOffsets[1].z += region.extent.depth;
2062*03ce13f7SAndroid Build Coastguard Worker 
2063*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.dstOffsets[0] = blitRegion.dstOffsets[1] = region.dstOffset;
2064*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.dstOffsets[1].x += region.extent.width;
2065*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.dstOffsets[1].y += region.extent.height;
2066*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.dstOffsets[1].z += region.extent.depth;
2067*03ce13f7SAndroid Build Coastguard Worker 
2068*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.srcSubresource = region.srcSubresource;
2069*03ce13f7SAndroid Build Coastguard Worker 	blitRegion.dstSubresource = region.dstSubresource;
2070*03ce13f7SAndroid Build Coastguard Worker 
2071*03ce13f7SAndroid Build Coastguard Worker 	blit(src, dst, blitRegion, VK_FILTER_NEAREST);
2072*03ce13f7SAndroid Build Coastguard Worker }
2073*03ce13f7SAndroid Build Coastguard Worker 
averageByte4(uint32_t x,uint32_t y)2074*03ce13f7SAndroid Build Coastguard Worker static inline uint32_t averageByte4(uint32_t x, uint32_t y)
2075*03ce13f7SAndroid Build Coastguard Worker {
2076*03ce13f7SAndroid Build Coastguard Worker 	return (x & y) + (((x ^ y) >> 1) & 0x7F7F7F7F) + ((x ^ y) & 0x01010101);
2077*03ce13f7SAndroid Build Coastguard Worker }
2078*03ce13f7SAndroid Build Coastguard Worker 
fastResolve(const vk::Image * src,vk::Image * dst,VkImageResolve2KHR region)2079*03ce13f7SAndroid Build Coastguard Worker bool Blitter::fastResolve(const vk::Image *src, vk::Image *dst, VkImageResolve2KHR region)
2080*03ce13f7SAndroid Build Coastguard Worker {
2081*03ce13f7SAndroid Build Coastguard Worker 	if(region.dstOffset != VkOffset3D{ 0, 0, 0 })
2082*03ce13f7SAndroid Build Coastguard Worker 	{
2083*03ce13f7SAndroid Build Coastguard Worker 		return false;
2084*03ce13f7SAndroid Build Coastguard Worker 	}
2085*03ce13f7SAndroid Build Coastguard Worker 
2086*03ce13f7SAndroid Build Coastguard Worker 	if(region.srcOffset != VkOffset3D{ 0, 0, 0 })
2087*03ce13f7SAndroid Build Coastguard Worker 	{
2088*03ce13f7SAndroid Build Coastguard Worker 		return false;
2089*03ce13f7SAndroid Build Coastguard Worker 	}
2090*03ce13f7SAndroid Build Coastguard Worker 
2091*03ce13f7SAndroid Build Coastguard Worker 	if(region.srcSubresource.layerCount != 1)
2092*03ce13f7SAndroid Build Coastguard Worker 	{
2093*03ce13f7SAndroid Build Coastguard Worker 		return false;
2094*03ce13f7SAndroid Build Coastguard Worker 	}
2095*03ce13f7SAndroid Build Coastguard Worker 
2096*03ce13f7SAndroid Build Coastguard Worker 	if(region.extent != src->getExtent() ||
2097*03ce13f7SAndroid Build Coastguard Worker 	   region.extent != dst->getExtent() ||
2098*03ce13f7SAndroid Build Coastguard Worker 	   region.extent.depth != 1)
2099*03ce13f7SAndroid Build Coastguard Worker 	{
2100*03ce13f7SAndroid Build Coastguard Worker 		return false;
2101*03ce13f7SAndroid Build Coastguard Worker 	}
2102*03ce13f7SAndroid Build Coastguard Worker 
2103*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource srcSubresource = {
2104*03ce13f7SAndroid Build Coastguard Worker 		region.srcSubresource.aspectMask,
2105*03ce13f7SAndroid Build Coastguard Worker 		region.srcSubresource.mipLevel,
2106*03ce13f7SAndroid Build Coastguard Worker 		region.srcSubresource.baseArrayLayer
2107*03ce13f7SAndroid Build Coastguard Worker 	};
2108*03ce13f7SAndroid Build Coastguard Worker 
2109*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource dstSubresource = {
2110*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.aspectMask,
2111*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.mipLevel,
2112*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.baseArrayLayer
2113*03ce13f7SAndroid Build Coastguard Worker 	};
2114*03ce13f7SAndroid Build Coastguard Worker 
2115*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresourceRange dstSubresourceRange = {
2116*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.aspectMask,
2117*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.mipLevel,
2118*03ce13f7SAndroid Build Coastguard Worker 		1,  // levelCount
2119*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.baseArrayLayer,
2120*03ce13f7SAndroid Build Coastguard Worker 		region.dstSubresource.layerCount
2121*03ce13f7SAndroid Build Coastguard Worker 	};
2122*03ce13f7SAndroid Build Coastguard Worker 
2123*03ce13f7SAndroid Build Coastguard Worker 	void *source = src->getTexelPointer({ 0, 0, 0 }, srcSubresource);
2124*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *dest = reinterpret_cast<uint8_t *>(dst->getTexelPointer({ 0, 0, 0 }, dstSubresource));
2125*03ce13f7SAndroid Build Coastguard Worker 
2126*03ce13f7SAndroid Build Coastguard Worker 	auto format = src->getFormat();
2127*03ce13f7SAndroid Build Coastguard Worker 	auto samples = src->getSampleCount();
2128*03ce13f7SAndroid Build Coastguard Worker 	auto extent = src->getExtent();
2129*03ce13f7SAndroid Build Coastguard Worker 
2130*03ce13f7SAndroid Build Coastguard Worker 	int width = extent.width;
2131*03ce13f7SAndroid Build Coastguard Worker 	int height = extent.height;
2132*03ce13f7SAndroid Build Coastguard Worker 	int pitch = src->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, region.srcSubresource.mipLevel);
2133*03ce13f7SAndroid Build Coastguard Worker 	int slice = src->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, region.srcSubresource.mipLevel);
2134*03ce13f7SAndroid Build Coastguard Worker 
2135*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *source0 = (uint8_t *)source;
2136*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *source1 = source0 + slice;
2137*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *source2 = source1 + slice;
2138*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *source3 = source2 + slice;
2139*03ce13f7SAndroid Build Coastguard Worker 
2140*03ce13f7SAndroid Build Coastguard Worker 	[[maybe_unused]] const bool SSE2 = CPUID::supportsSSE2();
2141*03ce13f7SAndroid Build Coastguard Worker 
2142*03ce13f7SAndroid Build Coastguard Worker 	if(format == VK_FORMAT_R8G8B8A8_UNORM || format == VK_FORMAT_B8G8R8A8_UNORM || format == VK_FORMAT_A8B8G8R8_UNORM_PACK32)
2143*03ce13f7SAndroid Build Coastguard Worker 	{
2144*03ce13f7SAndroid Build Coastguard Worker 		if(samples == 4)
2145*03ce13f7SAndroid Build Coastguard Worker 		{
2146*03ce13f7SAndroid Build Coastguard Worker 			for(int y = 0; y < height; y++)
2147*03ce13f7SAndroid Build Coastguard Worker 			{
2148*03ce13f7SAndroid Build Coastguard Worker 				int x = 0;
2149*03ce13f7SAndroid Build Coastguard Worker 
2150*03ce13f7SAndroid Build Coastguard Worker #if defined(__i386__) || defined(__x86_64__)
2151*03ce13f7SAndroid Build Coastguard Worker 				if(SSE2)
2152*03ce13f7SAndroid Build Coastguard Worker 				{
2153*03ce13f7SAndroid Build Coastguard Worker 					for(; (x + 3) < width; x += 4)
2154*03ce13f7SAndroid Build Coastguard Worker 					{
2155*03ce13f7SAndroid Build Coastguard Worker 						__m128i c0 = _mm_loadu_si128((__m128i *)(source0 + 4 * x));
2156*03ce13f7SAndroid Build Coastguard Worker 						__m128i c1 = _mm_loadu_si128((__m128i *)(source1 + 4 * x));
2157*03ce13f7SAndroid Build Coastguard Worker 						__m128i c2 = _mm_loadu_si128((__m128i *)(source2 + 4 * x));
2158*03ce13f7SAndroid Build Coastguard Worker 						__m128i c3 = _mm_loadu_si128((__m128i *)(source3 + 4 * x));
2159*03ce13f7SAndroid Build Coastguard Worker 
2160*03ce13f7SAndroid Build Coastguard Worker 						c0 = _mm_avg_epu8(c0, c1);
2161*03ce13f7SAndroid Build Coastguard Worker 						c2 = _mm_avg_epu8(c2, c3);
2162*03ce13f7SAndroid Build Coastguard Worker 						c0 = _mm_avg_epu8(c0, c2);
2163*03ce13f7SAndroid Build Coastguard Worker 
2164*03ce13f7SAndroid Build Coastguard Worker 						_mm_storeu_si128((__m128i *)(dest + 4 * x), c0);
2165*03ce13f7SAndroid Build Coastguard Worker 					}
2166*03ce13f7SAndroid Build Coastguard Worker 				}
2167*03ce13f7SAndroid Build Coastguard Worker #endif
2168*03ce13f7SAndroid Build Coastguard Worker 
2169*03ce13f7SAndroid Build Coastguard Worker 				for(; x < width; x++)
2170*03ce13f7SAndroid Build Coastguard Worker 				{
2171*03ce13f7SAndroid Build Coastguard Worker 					uint32_t c0 = *(uint32_t *)(source0 + 4 * x);
2172*03ce13f7SAndroid Build Coastguard Worker 					uint32_t c1 = *(uint32_t *)(source1 + 4 * x);
2173*03ce13f7SAndroid Build Coastguard Worker 					uint32_t c2 = *(uint32_t *)(source2 + 4 * x);
2174*03ce13f7SAndroid Build Coastguard Worker 					uint32_t c3 = *(uint32_t *)(source3 + 4 * x);
2175*03ce13f7SAndroid Build Coastguard Worker 
2176*03ce13f7SAndroid Build Coastguard Worker 					uint32_t c01 = averageByte4(c0, c1);
2177*03ce13f7SAndroid Build Coastguard Worker 					uint32_t c23 = averageByte4(c2, c3);
2178*03ce13f7SAndroid Build Coastguard Worker 					uint32_t c03 = averageByte4(c01, c23);
2179*03ce13f7SAndroid Build Coastguard Worker 
2180*03ce13f7SAndroid Build Coastguard Worker 					*(uint32_t *)(dest + 4 * x) = c03;
2181*03ce13f7SAndroid Build Coastguard Worker 				}
2182*03ce13f7SAndroid Build Coastguard Worker 
2183*03ce13f7SAndroid Build Coastguard Worker 				source0 += pitch;
2184*03ce13f7SAndroid Build Coastguard Worker 				source1 += pitch;
2185*03ce13f7SAndroid Build Coastguard Worker 				source2 += pitch;
2186*03ce13f7SAndroid Build Coastguard Worker 				source3 += pitch;
2187*03ce13f7SAndroid Build Coastguard Worker 				dest += pitch;
2188*03ce13f7SAndroid Build Coastguard Worker 
2189*03ce13f7SAndroid Build Coastguard Worker 				ASSERT(source0 < src->end());
2190*03ce13f7SAndroid Build Coastguard Worker 				ASSERT(source3 < src->end());
2191*03ce13f7SAndroid Build Coastguard Worker 				ASSERT(dest < dst->end());
2192*03ce13f7SAndroid Build Coastguard Worker 			}
2193*03ce13f7SAndroid Build Coastguard Worker 		}
2194*03ce13f7SAndroid Build Coastguard Worker 		else
2195*03ce13f7SAndroid Build Coastguard Worker 			UNSUPPORTED("Samples: %d", samples);
2196*03ce13f7SAndroid Build Coastguard Worker 	}
2197*03ce13f7SAndroid Build Coastguard Worker 	else
2198*03ce13f7SAndroid Build Coastguard Worker 	{
2199*03ce13f7SAndroid Build Coastguard Worker 		return false;
2200*03ce13f7SAndroid Build Coastguard Worker 	}
2201*03ce13f7SAndroid Build Coastguard Worker 
2202*03ce13f7SAndroid Build Coastguard Worker 	dst->contentsChanged(dstSubresourceRange);
2203*03ce13f7SAndroid Build Coastguard Worker 
2204*03ce13f7SAndroid Build Coastguard Worker 	return true;
2205*03ce13f7SAndroid Build Coastguard Worker }
2206*03ce13f7SAndroid Build Coastguard Worker 
copy(const vk::Image * src,uint8_t * dst,unsigned int dstPitch)2207*03ce13f7SAndroid Build Coastguard Worker void Blitter::copy(const vk::Image *src, uint8_t *dst, unsigned int dstPitch)
2208*03ce13f7SAndroid Build Coastguard Worker {
2209*03ce13f7SAndroid Build Coastguard Worker 	VkExtent3D extent = src->getExtent();
2210*03ce13f7SAndroid Build Coastguard Worker 	size_t rowBytes = src->getFormat(VK_IMAGE_ASPECT_COLOR_BIT).bytes() * extent.width;
2211*03ce13f7SAndroid Build Coastguard Worker 	unsigned int srcPitch = src->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
2212*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(dstPitch >= rowBytes && srcPitch >= rowBytes && src->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0).height >= extent.height);
2213*03ce13f7SAndroid Build Coastguard Worker 
2214*03ce13f7SAndroid Build Coastguard Worker 	const uint8_t *s = (uint8_t *)src->getTexelPointer({ 0, 0, 0 }, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 });
2215*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *d = dst;
2216*03ce13f7SAndroid Build Coastguard Worker 
2217*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t y = 0; y < extent.height; y++)
2218*03ce13f7SAndroid Build Coastguard Worker 	{
2219*03ce13f7SAndroid Build Coastguard Worker 		memcpy(d, s, rowBytes);
2220*03ce13f7SAndroid Build Coastguard Worker 
2221*03ce13f7SAndroid Build Coastguard Worker 		s += srcPitch;
2222*03ce13f7SAndroid Build Coastguard Worker 		d += dstPitch;
2223*03ce13f7SAndroid Build Coastguard Worker 	}
2224*03ce13f7SAndroid Build Coastguard Worker }
2225*03ce13f7SAndroid Build Coastguard Worker 
computeCubeCorner(Pointer<Byte> & layer,Int & x0,Int & x1,Int & y0,Int & y1,Int & pitchB,const State & state)2226*03ce13f7SAndroid Build Coastguard Worker void Blitter::computeCubeCorner(Pointer<Byte> &layer, Int &x0, Int &x1, Int &y0, Int &y1, Int &pitchB, const State &state)
2227*03ce13f7SAndroid Build Coastguard Worker {
2228*03ce13f7SAndroid Build Coastguard Worker 	int bytes = state.sourceFormat.bytes();
2229*03ce13f7SAndroid Build Coastguard Worker 
2230*03ce13f7SAndroid Build Coastguard Worker 	Float4 c = readFloat4(layer + ComputeOffset(x0, y1, pitchB, bytes), state) +
2231*03ce13f7SAndroid Build Coastguard Worker 	           readFloat4(layer + ComputeOffset(x1, y0, pitchB, bytes), state) +
2232*03ce13f7SAndroid Build Coastguard Worker 	           readFloat4(layer + ComputeOffset(x1, y1, pitchB, bytes), state);
2233*03ce13f7SAndroid Build Coastguard Worker 
2234*03ce13f7SAndroid Build Coastguard Worker 	c *= Float4(1.0f / 3.0f);
2235*03ce13f7SAndroid Build Coastguard Worker 
2236*03ce13f7SAndroid Build Coastguard Worker 	write(c, layer + ComputeOffset(x0, y0, pitchB, bytes), state);
2237*03ce13f7SAndroid Build Coastguard Worker }
2238*03ce13f7SAndroid Build Coastguard Worker 
generateCornerUpdate(const State & state)2239*03ce13f7SAndroid Build Coastguard Worker Blitter::CornerUpdateRoutineType Blitter::generateCornerUpdate(const State &state)
2240*03ce13f7SAndroid Build Coastguard Worker {
2241*03ce13f7SAndroid Build Coastguard Worker 	// Reading and writing from/to the same image
2242*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(state.sourceFormat == state.destFormat);
2243*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(state.srcSamples == state.destSamples);
2244*03ce13f7SAndroid Build Coastguard Worker 
2245*03ce13f7SAndroid Build Coastguard Worker 	// Vulkan 1.2: "If samples is not VK_SAMPLE_COUNT_1_BIT, then imageType must be
2246*03ce13f7SAndroid Build Coastguard Worker 	// VK_IMAGE_TYPE_2D, flags must not contain VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT"
2247*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(state.srcSamples == 1);
2248*03ce13f7SAndroid Build Coastguard Worker 
2249*03ce13f7SAndroid Build Coastguard Worker 	CornerUpdateFunction function;
2250*03ce13f7SAndroid Build Coastguard Worker 	{
2251*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> blit(function.Arg<0>());
2252*03ce13f7SAndroid Build Coastguard Worker 
2253*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> layers = *Pointer<Pointer<Byte>>(blit + OFFSET(CubeBorderData, layers));
2254*03ce13f7SAndroid Build Coastguard Worker 		Int pitchB = *Pointer<Int>(blit + OFFSET(CubeBorderData, pitchB));
2255*03ce13f7SAndroid Build Coastguard Worker 		UInt layerSize = *Pointer<Int>(blit + OFFSET(CubeBorderData, layerSize));
2256*03ce13f7SAndroid Build Coastguard Worker 		UInt dim = *Pointer<Int>(blit + OFFSET(CubeBorderData, dim));
2257*03ce13f7SAndroid Build Coastguard Worker 
2258*03ce13f7SAndroid Build Coastguard Worker 		// Low Border, Low Pixel, High Border, High Pixel
2259*03ce13f7SAndroid Build Coastguard Worker 		Int LB(-1), LP(0), HB(dim), HP(dim - 1);
2260*03ce13f7SAndroid Build Coastguard Worker 
2261*03ce13f7SAndroid Build Coastguard Worker 		for(int face = 0; face < 6; face++)
2262*03ce13f7SAndroid Build Coastguard Worker 		{
2263*03ce13f7SAndroid Build Coastguard Worker 			computeCubeCorner(layers, LB, LP, LB, LP, pitchB, state);
2264*03ce13f7SAndroid Build Coastguard Worker 			computeCubeCorner(layers, LB, LP, HB, HP, pitchB, state);
2265*03ce13f7SAndroid Build Coastguard Worker 			computeCubeCorner(layers, HB, HP, LB, LP, pitchB, state);
2266*03ce13f7SAndroid Build Coastguard Worker 			computeCubeCorner(layers, HB, HP, HB, HP, pitchB, state);
2267*03ce13f7SAndroid Build Coastguard Worker 			layers = layers + layerSize;
2268*03ce13f7SAndroid Build Coastguard Worker 		}
2269*03ce13f7SAndroid Build Coastguard Worker 	}
2270*03ce13f7SAndroid Build Coastguard Worker 
2271*03ce13f7SAndroid Build Coastguard Worker 	return function("BlitRoutine");
2272*03ce13f7SAndroid Build Coastguard Worker }
2273*03ce13f7SAndroid Build Coastguard Worker 
updateBorders(const vk::Image * image,const VkImageSubresource & subresource)2274*03ce13f7SAndroid Build Coastguard Worker void Blitter::updateBorders(const vk::Image *image, const VkImageSubresource &subresource)
2275*03ce13f7SAndroid Build Coastguard Worker {
2276*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(image->getArrayLayers() >= (subresource.arrayLayer + 6));
2277*03ce13f7SAndroid Build Coastguard Worker 
2278*03ce13f7SAndroid Build Coastguard Worker 	// From Vulkan 1.1 spec, section 11.5. Image Views:
2279*03ce13f7SAndroid Build Coastguard Worker 	// "For cube and cube array image views, the layers of the image view starting
2280*03ce13f7SAndroid Build Coastguard Worker 	//  at baseArrayLayer correspond to faces in the order +X, -X, +Y, -Y, +Z, -Z."
2281*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource posX = subresource;
2282*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource negX = posX;
2283*03ce13f7SAndroid Build Coastguard Worker 	negX.arrayLayer++;
2284*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource posY = negX;
2285*03ce13f7SAndroid Build Coastguard Worker 	posY.arrayLayer++;
2286*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource negY = posY;
2287*03ce13f7SAndroid Build Coastguard Worker 	negY.arrayLayer++;
2288*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource posZ = negY;
2289*03ce13f7SAndroid Build Coastguard Worker 	posZ.arrayLayer++;
2290*03ce13f7SAndroid Build Coastguard Worker 	VkImageSubresource negZ = posZ;
2291*03ce13f7SAndroid Build Coastguard Worker 	negZ.arrayLayer++;
2292*03ce13f7SAndroid Build Coastguard Worker 
2293*03ce13f7SAndroid Build Coastguard Worker 	// Copy top / bottom
2294*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posX, BOTTOM, negY, RIGHT);
2295*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posY, BOTTOM, posZ, TOP);
2296*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posZ, BOTTOM, negY, TOP);
2297*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negX, BOTTOM, negY, LEFT);
2298*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negY, BOTTOM, negZ, BOTTOM);
2299*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negZ, BOTTOM, negY, BOTTOM);
2300*03ce13f7SAndroid Build Coastguard Worker 
2301*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posX, TOP, posY, RIGHT);
2302*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posY, TOP, negZ, TOP);
2303*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posZ, TOP, posY, BOTTOM);
2304*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negX, TOP, posY, LEFT);
2305*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negY, TOP, posZ, BOTTOM);
2306*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negZ, TOP, posY, TOP);
2307*03ce13f7SAndroid Build Coastguard Worker 
2308*03ce13f7SAndroid Build Coastguard Worker 	// Copy left / right
2309*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posX, RIGHT, negZ, LEFT);
2310*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posY, RIGHT, posX, TOP);
2311*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posZ, RIGHT, posX, LEFT);
2312*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negX, RIGHT, posZ, LEFT);
2313*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negY, RIGHT, posX, BOTTOM);
2314*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negZ, RIGHT, negX, LEFT);
2315*03ce13f7SAndroid Build Coastguard Worker 
2316*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posX, LEFT, posZ, RIGHT);
2317*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posY, LEFT, negX, TOP);
2318*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, posZ, LEFT, negX, RIGHT);
2319*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negX, LEFT, negZ, RIGHT);
2320*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negY, LEFT, negX, BOTTOM);
2321*03ce13f7SAndroid Build Coastguard Worker 	copyCubeEdge(image, negZ, LEFT, posX, RIGHT);
2322*03ce13f7SAndroid Build Coastguard Worker 
2323*03ce13f7SAndroid Build Coastguard Worker 	// Compute corner colors
2324*03ce13f7SAndroid Build Coastguard Worker 	VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
2325*03ce13f7SAndroid Build Coastguard Worker 	vk::Format format = image->getFormat(aspect);
2326*03ce13f7SAndroid Build Coastguard Worker 	VkSampleCountFlagBits samples = image->getSampleCount();
2327*03ce13f7SAndroid Build Coastguard Worker 	State state(format, format, samples, samples, Options{ 0xF });
2328*03ce13f7SAndroid Build Coastguard Worker 
2329*03ce13f7SAndroid Build Coastguard Worker 	// Vulkan 1.2: "If samples is not VK_SAMPLE_COUNT_1_BIT, then imageType must be
2330*03ce13f7SAndroid Build Coastguard Worker 	// VK_IMAGE_TYPE_2D, flags must not contain VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT"
2331*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(samples == VK_SAMPLE_COUNT_1_BIT);
2332*03ce13f7SAndroid Build Coastguard Worker 
2333*03ce13f7SAndroid Build Coastguard Worker 	auto cornerUpdateRoutine = getCornerUpdateRoutine(state);
2334*03ce13f7SAndroid Build Coastguard Worker 	if(!cornerUpdateRoutine)
2335*03ce13f7SAndroid Build Coastguard Worker 	{
2336*03ce13f7SAndroid Build Coastguard Worker 		return;
2337*03ce13f7SAndroid Build Coastguard Worker 	}
2338*03ce13f7SAndroid Build Coastguard Worker 
2339*03ce13f7SAndroid Build Coastguard Worker 	VkExtent3D extent = image->getMipLevelExtent(aspect, subresource.mipLevel);
2340*03ce13f7SAndroid Build Coastguard Worker 	CubeBorderData data = {
2341*03ce13f7SAndroid Build Coastguard Worker 		image->getTexelPointer({ 0, 0, 0 }, posX),
2342*03ce13f7SAndroid Build Coastguard Worker 		assert_cast<uint32_t>(image->rowPitchBytes(aspect, subresource.mipLevel)),
2343*03ce13f7SAndroid Build Coastguard Worker 		assert_cast<uint32_t>(image->getLayerSize(aspect)),
2344*03ce13f7SAndroid Build Coastguard Worker 		extent.width
2345*03ce13f7SAndroid Build Coastguard Worker 	};
2346*03ce13f7SAndroid Build Coastguard Worker 	cornerUpdateRoutine(&data);
2347*03ce13f7SAndroid Build Coastguard Worker }
2348*03ce13f7SAndroid Build Coastguard Worker 
copyCubeEdge(const vk::Image * image,const VkImageSubresource & dstSubresource,Edge dstEdge,const VkImageSubresource & srcSubresource,Edge srcEdge)2349*03ce13f7SAndroid Build Coastguard Worker void Blitter::copyCubeEdge(const vk::Image *image,
2350*03ce13f7SAndroid Build Coastguard Worker                            const VkImageSubresource &dstSubresource, Edge dstEdge,
2351*03ce13f7SAndroid Build Coastguard Worker                            const VkImageSubresource &srcSubresource, Edge srcEdge)
2352*03ce13f7SAndroid Build Coastguard Worker {
2353*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(srcSubresource.aspectMask == dstSubresource.aspectMask);
2354*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(srcSubresource.mipLevel == dstSubresource.mipLevel);
2355*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(srcSubresource.arrayLayer != dstSubresource.arrayLayer);
2356*03ce13f7SAndroid Build Coastguard Worker 
2357*03ce13f7SAndroid Build Coastguard Worker 	// Figure out if the edges to be copied in reverse order respectively from one another
2358*03ce13f7SAndroid Build Coastguard Worker 	// The copy should be reversed whenever the same edges are contiguous or if we're
2359*03ce13f7SAndroid Build Coastguard Worker 	// copying top <-> right or bottom <-> left. This is explained by the layout, which is:
2360*03ce13f7SAndroid Build Coastguard Worker 	//
2361*03ce13f7SAndroid Build Coastguard Worker 	//      | +y |
2362*03ce13f7SAndroid Build Coastguard Worker 	// | -x | +z | +x | -z |
2363*03ce13f7SAndroid Build Coastguard Worker 	//      | -y |
2364*03ce13f7SAndroid Build Coastguard Worker 
2365*03ce13f7SAndroid Build Coastguard Worker 	bool reverse = (srcEdge == dstEdge) ||
2366*03ce13f7SAndroid Build Coastguard Worker 	               ((srcEdge == TOP) && (dstEdge == RIGHT)) ||
2367*03ce13f7SAndroid Build Coastguard Worker 	               ((srcEdge == RIGHT) && (dstEdge == TOP)) ||
2368*03ce13f7SAndroid Build Coastguard Worker 	               ((srcEdge == BOTTOM) && (dstEdge == LEFT)) ||
2369*03ce13f7SAndroid Build Coastguard Worker 	               ((srcEdge == LEFT) && (dstEdge == BOTTOM));
2370*03ce13f7SAndroid Build Coastguard Worker 
2371*03ce13f7SAndroid Build Coastguard Worker 	VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(srcSubresource.aspectMask);
2372*03ce13f7SAndroid Build Coastguard Worker 	int bytes = image->getFormat(aspect).bytes();
2373*03ce13f7SAndroid Build Coastguard Worker 	int pitchB = image->rowPitchBytes(aspect, srcSubresource.mipLevel);
2374*03ce13f7SAndroid Build Coastguard Worker 
2375*03ce13f7SAndroid Build Coastguard Worker 	VkExtent3D extent = image->getMipLevelExtent(aspect, srcSubresource.mipLevel);
2376*03ce13f7SAndroid Build Coastguard Worker 	int w = extent.width;
2377*03ce13f7SAndroid Build Coastguard Worker 	int h = extent.height;
2378*03ce13f7SAndroid Build Coastguard Worker 	if(w != h)
2379*03ce13f7SAndroid Build Coastguard Worker 	{
2380*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("Cube doesn't have square faces : (%d, %d)", w, h);
2381*03ce13f7SAndroid Build Coastguard Worker 	}
2382*03ce13f7SAndroid Build Coastguard Worker 
2383*03ce13f7SAndroid Build Coastguard Worker 	// Src is expressed in the regular [0, width-1], [0, height-1] space
2384*03ce13f7SAndroid Build Coastguard Worker 	bool srcHorizontal = ((srcEdge == TOP) || (srcEdge == BOTTOM));
2385*03ce13f7SAndroid Build Coastguard Worker 	int srcDelta = srcHorizontal ? bytes : pitchB;
2386*03ce13f7SAndroid Build Coastguard Worker 	VkOffset3D srcOffset = { (srcEdge == RIGHT) ? (w - 1) : 0, (srcEdge == BOTTOM) ? (h - 1) : 0, 0 };
2387*03ce13f7SAndroid Build Coastguard Worker 
2388*03ce13f7SAndroid Build Coastguard Worker 	// Dst contains borders, so it is expressed in the [-1, width], [-1, height] space
2389*03ce13f7SAndroid Build Coastguard Worker 	bool dstHorizontal = ((dstEdge == TOP) || (dstEdge == BOTTOM));
2390*03ce13f7SAndroid Build Coastguard Worker 	int dstDelta = (dstHorizontal ? bytes : pitchB) * (reverse ? -1 : 1);
2391*03ce13f7SAndroid Build Coastguard Worker 	VkOffset3D dstOffset = { (dstEdge == RIGHT) ? w : -1, (dstEdge == BOTTOM) ? h : -1, 0 };
2392*03ce13f7SAndroid Build Coastguard Worker 
2393*03ce13f7SAndroid Build Coastguard Worker 	// Don't write in the corners
2394*03ce13f7SAndroid Build Coastguard Worker 	if(dstHorizontal)
2395*03ce13f7SAndroid Build Coastguard Worker 	{
2396*03ce13f7SAndroid Build Coastguard Worker 		dstOffset.x += reverse ? w : 1;
2397*03ce13f7SAndroid Build Coastguard Worker 	}
2398*03ce13f7SAndroid Build Coastguard Worker 	else
2399*03ce13f7SAndroid Build Coastguard Worker 	{
2400*03ce13f7SAndroid Build Coastguard Worker 		dstOffset.y += reverse ? h : 1;
2401*03ce13f7SAndroid Build Coastguard Worker 	}
2402*03ce13f7SAndroid Build Coastguard Worker 
2403*03ce13f7SAndroid Build Coastguard Worker 	const uint8_t *src = static_cast<const uint8_t *>(image->getTexelPointer(srcOffset, srcSubresource));
2404*03ce13f7SAndroid Build Coastguard Worker 	uint8_t *dst = static_cast<uint8_t *>(image->getTexelPointer(dstOffset, dstSubresource));
2405*03ce13f7SAndroid Build Coastguard Worker 	ASSERT((src < image->end()) && ((src + (w * srcDelta)) < image->end()));
2406*03ce13f7SAndroid Build Coastguard Worker 	ASSERT((dst < image->end()) && ((dst + (w * dstDelta)) < image->end()));
2407*03ce13f7SAndroid Build Coastguard Worker 
2408*03ce13f7SAndroid Build Coastguard Worker 	for(int i = 0; i < w; ++i, dst += dstDelta, src += srcDelta)
2409*03ce13f7SAndroid Build Coastguard Worker 	{
2410*03ce13f7SAndroid Build Coastguard Worker 		memcpy(dst, src, bytes);
2411*03ce13f7SAndroid Build Coastguard Worker 	}
2412*03ce13f7SAndroid Build Coastguard Worker }
2413*03ce13f7SAndroid Build Coastguard Worker 
2414*03ce13f7SAndroid Build Coastguard Worker }  // namespace sw
2415