blob: 63c6040cc1eb4fb657b5dd11baaa005a9ae9be05 [file] [log] [blame]
Nicolas Capens68a82382018-10-02 13:16:55 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "Blitter.hpp"
16
Nicolas Capens1d8c8db2018-11-05 16:30:42 -050017#include "Pipeline/ShaderCore.hpp"
Nicolas Capens68a82382018-10-02 13:16:55 -040018#include "Reactor/Reactor.hpp"
Nicolas Capens1d8c8db2018-11-05 16:30:42 -050019#include "System/Memory.hpp"
Chris Forbesebe5f7f2019-01-16 10:38:34 -080020#include "Vulkan/VkDebug.hpp"
Alexis Hetu33642272019-03-01 11:55:59 -050021#include "Vulkan/VkImage.hpp"
Chris Forbes529eda32019-05-08 10:27:05 -070022#include "Vulkan/VkBuffer.hpp"
Nicolas Capens68a82382018-10-02 13:16:55 -040023
Nicolas Capensb8c63932019-03-19 01:52:40 -040024#include <utility>
25
Nicolas Capens68a82382018-10-02 13:16:55 -040026namespace sw
27{
Alexis Hetuf60a2d52019-05-09 14:16:05 -040028 Blitter::Blitter() :
29 blitMutex(),
30 blitCache(1024),
31 cornerUpdateMutex(),
32 cornerUpdateCache(64) // We only need one of these per format
Nicolas Capens68a82382018-10-02 13:16:55 -040033 {
Nicolas Capens68a82382018-10-02 13:16:55 -040034 }
35
36 Blitter::~Blitter()
37 {
Nicolas Capens68a82382018-10-02 13:16:55 -040038 }
39
Alexis Hetu04dae5e2019-04-08 13:41:50 -040040 void Blitter::clear(void *pixel, vk::Format format, vk::Image *dest, const vk::Format& viewFormat, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea)
Alexis Hetu33642272019-03-01 11:55:59 -050041 {
42 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask);
Nicolas Capenscfe11c72019-05-16 09:58:26 -040043 vk::Format dstFormat = viewFormat.getAspectFormat(aspect);
Alexis Hetu04dae5e2019-04-08 13:41:50 -040044 if(dstFormat == VK_FORMAT_UNDEFINED)
Alexis Hetu33642272019-03-01 11:55:59 -050045 {
46 return;
47 }
48
Alexis Hetu04dae5e2019-04-08 13:41:50 -040049 if(fastClear(pixel, format, dest, dstFormat, subresourceRange, renderArea))
Alexis Hetu33642272019-03-01 11:55:59 -050050 {
51 return;
52 }
53
Alexis Hetu04dae5e2019-04-08 13:41:50 -040054 State state(format, dstFormat, 1, dest->getSampleCountFlagBits(), { 0xF });
Alexis Hetuf60a2d52019-05-09 14:16:05 -040055 Routine *blitRoutine = getBlitRoutine(state);
Alexis Hetu33642272019-03-01 11:55:59 -050056 if(!blitRoutine)
57 {
58 return;
59 }
60
61 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
62
63 VkImageSubresourceLayers subresLayers =
64 {
65 subresourceRange.aspectMask,
66 subresourceRange.baseMipLevel,
67 subresourceRange.baseArrayLayer,
68 1
69 };
70
71 uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange);
72 uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange);
73
74 VkRect2D area = { { 0, 0 }, { 0, 0 } };
75 if(renderArea)
76 {
77 ASSERT(subresourceRange.levelCount == 1);
78 area = *renderArea;
79 }
80
81 for(; subresLayers.mipLevel <= lastMipLevel; subresLayers.mipLevel++)
82 {
Nicolas Capensba873302019-05-16 11:25:27 -040083 VkExtent3D extent = dest->getMipLevelExtent(aspect, subresLayers.mipLevel);
Alexis Hetu33642272019-03-01 11:55:59 -050084 if(!renderArea)
85 {
86 area.extent.width = extent.width;
87 area.extent.height = extent.height;
88 }
89
90 BlitData data =
91 {
92 pixel, nullptr, // source, dest
93
Alexis Hetu25ec7b02019-03-12 14:19:22 -040094 format.bytes(), // sPitchB
Alexis Hetu33642272019-03-01 11:55:59 -050095 dest->rowPitchBytes(aspect, subresLayers.mipLevel), // dPitchB
Alexis Hetu54ec7592019-03-20 14:37:16 -040096 0, // sSliceB (unused in clear operations)
Alexis Hetu33642272019-03-01 11:55:59 -050097 dest->slicePitchBytes(aspect, subresLayers.mipLevel), // dSliceB
98
99 0.5f, 0.5f, 0.0f, 0.0f, // x0, y0, w, h
100
101 area.offset.y, static_cast<int>(area.offset.y + area.extent.height), // y0d, y1d
102 area.offset.x, static_cast<int>(area.offset.x + area.extent.width), // x0d, x1d
103
104 0, 0, // sWidth, sHeight
105 };
106
Chris Forbes15bf1ef2019-05-02 17:19:12 -0700107 if (renderArea && dest->is3DSlice())
Alexis Hetu33642272019-03-01 11:55:59 -0500108 {
Chris Forbes15bf1ef2019-05-02 17:19:12 -0700109 // Reinterpret layers as depth slices
110 subresLayers.baseArrayLayer = 0;
111 subresLayers.layerCount = 1;
112 for (uint32_t depth = subresourceRange.baseArrayLayer; depth <= lastLayer; depth++)
Alexis Hetu33642272019-03-01 11:55:59 -0500113 {
Chris Forbes15bf1ef2019-05-02 17:19:12 -0700114 data.dest = dest->getTexelPointer({0, 0, static_cast<int32_t>(depth)}, subresLayers);
Alexis Hetu33642272019-03-01 11:55:59 -0500115 blitFunction(&data);
116 }
117 }
Chris Forbes15bf1ef2019-05-02 17:19:12 -0700118 else
119 {
120 for(subresLayers.baseArrayLayer = subresourceRange.baseArrayLayer; subresLayers.baseArrayLayer <= lastLayer; subresLayers.baseArrayLayer++)
121 {
122 for(uint32_t depth = 0; depth < extent.depth; depth++)
123 {
124 data.dest = dest->getTexelPointer({ 0, 0, static_cast<int32_t>(depth) }, subresLayers);
125
126 blitFunction(&data);
127 }
128 }
129 }
Alexis Hetu33642272019-03-01 11:55:59 -0500130 }
131 }
132
Alexis Hetu04dae5e2019-04-08 13:41:50 -0400133 bool Blitter::fastClear(void *pixel, vk::Format format, vk::Image *dest, const vk::Format& viewFormat, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea)
Alexis Hetu33642272019-03-01 11:55:59 -0500134 {
135 if(format != VK_FORMAT_R32G32B32A32_SFLOAT)
136 {
137 return false;
138 }
139
140 float *color = (float*)pixel;
141 float r = color[0];
142 float g = color[1];
143 float b = color[2];
144 float a = color[3];
145
146 uint32_t packed;
147
148 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask);
Alexis Hetu04dae5e2019-04-08 13:41:50 -0400149 switch(viewFormat)
Alexis Hetu33642272019-03-01 11:55:59 -0500150 {
151 case VK_FORMAT_R5G6B5_UNORM_PACK16:
152 packed = ((uint16_t)(31 * b + 0.5f) << 0) |
153 ((uint16_t)(63 * g + 0.5f) << 5) |
154 ((uint16_t)(31 * r + 0.5f) << 11);
155 break;
156 case VK_FORMAT_B5G6R5_UNORM_PACK16:
157 packed = ((uint16_t)(31 * r + 0.5f) << 0) |
158 ((uint16_t)(63 * g + 0.5f) << 5) |
159 ((uint16_t)(31 * b + 0.5f) << 11);
160 break;
161 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
162 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
163 case VK_FORMAT_R8G8B8A8_UNORM:
164 packed = ((uint32_t)(255 * a + 0.5f) << 24) |
165 ((uint32_t)(255 * b + 0.5f) << 16) |
166 ((uint32_t)(255 * g + 0.5f) << 8) |
167 ((uint32_t)(255 * r + 0.5f) << 0);
168 break;
169 case VK_FORMAT_B8G8R8A8_UNORM:
170 packed = ((uint32_t)(255 * a + 0.5f) << 24) |
171 ((uint32_t)(255 * r + 0.5f) << 16) |
172 ((uint32_t)(255 * g + 0.5f) << 8) |
173 ((uint32_t)(255 * b + 0.5f) << 0);
174 break;
175 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
176 packed = R11G11B10F(color);
177 break;
178 case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
179 packed = RGB9E5(color);
180 break;
181 default:
182 return false;
183 }
184
Ben Clayton00424c12019-03-17 17:29:30 +0000185 VkImageSubresourceLayers subresLayers =
Alexis Hetu33642272019-03-01 11:55:59 -0500186 {
187 subresourceRange.aspectMask,
188 subresourceRange.baseMipLevel,
189 subresourceRange.baseArrayLayer,
190 1
191 };
192 uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange);
193 uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange);
194
195 VkRect2D area = { { 0, 0 }, { 0, 0 } };
196 if(renderArea)
197 {
198 ASSERT(subresourceRange.levelCount == 1);
199 area = *renderArea;
200 }
201
202 for(; subresLayers.mipLevel <= lastMipLevel; subresLayers.mipLevel++)
203 {
204 int rowPitchBytes = dest->rowPitchBytes(aspect, subresLayers.mipLevel);
205 int slicePitchBytes = dest->slicePitchBytes(aspect, subresLayers.mipLevel);
Nicolas Capensba873302019-05-16 11:25:27 -0400206 VkExtent3D extent = dest->getMipLevelExtent(aspect, subresLayers.mipLevel);
Alexis Hetu33642272019-03-01 11:55:59 -0500207 if(!renderArea)
208 {
209 area.extent.width = extent.width;
210 area.extent.height = extent.height;
211 }
Alexis Hetu32ac8312019-04-15 17:20:29 -0400212 if(dest->is3DSlice())
213 {
214 extent.depth = 1; // The 3D image is instead interpreted as a 2D image with layers
215 }
Alexis Hetu33642272019-03-01 11:55:59 -0500216
217 for(subresLayers.baseArrayLayer = subresourceRange.baseArrayLayer; subresLayers.baseArrayLayer <= lastLayer; subresLayers.baseArrayLayer++)
218 {
219 for(uint32_t depth = 0; depth < extent.depth; depth++)
220 {
221 uint8_t *slice = (uint8_t*)dest->getTexelPointer(
222 { area.offset.x, area.offset.y, static_cast<int32_t>(depth) }, subresLayers);
223
224 for(int j = 0; j < dest->getSampleCountFlagBits(); j++)
225 {
226 uint8_t *d = slice;
227
Alexis Hetu04dae5e2019-04-08 13:41:50 -0400228 switch(viewFormat.bytes())
Alexis Hetu33642272019-03-01 11:55:59 -0500229 {
230 case 2:
231 for(uint32_t i = 0; i < area.extent.height; i++)
232 {
Alexis Hetu32ac8312019-04-15 17:20:29 -0400233 ASSERT(d < dest->end());
Alexis Hetu33642272019-03-01 11:55:59 -0500234 sw::clear((uint16_t*)d, packed, area.extent.width);
235 d += rowPitchBytes;
236 }
237 break;
238 case 4:
239 for(uint32_t i = 0; i < area.extent.height; i++)
240 {
Alexis Hetu32ac8312019-04-15 17:20:29 -0400241 ASSERT(d < dest->end());
Alexis Hetu33642272019-03-01 11:55:59 -0500242 sw::clear((uint32_t*)d, packed, area.extent.width);
243 d += rowPitchBytes;
244 }
245 break;
246 default:
247 assert(false);
248 }
249
250 slice += slicePitchBytes;
251 }
252 }
253 }
254 }
255
256 return true;
257 }
258
Nicolas Capens68a82382018-10-02 13:16:55 -0400259 bool Blitter::read(Float4 &c, Pointer<Byte> element, const State &state)
260 {
261 c = Float4(0.0f, 0.0f, 0.0f, 1.0f);
262
263 switch(state.sourceFormat)
264 {
Alexis Hetua28671d2018-12-19 17:23:26 -0500265 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
266 c.w = Float(Int(*Pointer<Byte>(element)) & Int(0xF));
267 c.x = Float((Int(*Pointer<Byte>(element)) >> 4) & Int(0xF));
268 c.y = Float(Int(*Pointer<Byte>(element + 1)) & Int(0xF));
269 c.z = Float((Int(*Pointer<Byte>(element + 1)) >> 4) & Int(0xF));
270 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500271 case VK_FORMAT_R8_SINT:
272 case VK_FORMAT_R8_SNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400273 c.x = Float(Int(*Pointer<SByte>(element)));
274 c.w = float(0x7F);
275 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500276 case VK_FORMAT_R8_UNORM:
277 case VK_FORMAT_R8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400278 c.x = Float(Int(*Pointer<Byte>(element)));
279 c.w = float(0xFF);
280 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500281 case VK_FORMAT_R16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400282 c.x = Float(Int(*Pointer<Short>(element)));
283 c.w = float(0x7FFF);
284 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500285 case VK_FORMAT_R16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400286 c.x = Float(Int(*Pointer<UShort>(element)));
287 c.w = float(0xFFFF);
288 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500289 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400290 c.x = Float(*Pointer<Int>(element));
291 c.w = float(0x7FFFFFFF);
292 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500293 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400294 c.x = Float(*Pointer<UInt>(element));
295 c.w = float(0xFFFFFFFF);
296 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500297 case VK_FORMAT_B8G8R8A8_SRGB:
Alexis Hetudd152e12018-11-14 13:39:28 -0500298 case VK_FORMAT_B8G8R8A8_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400299 c = Float4(*Pointer<Byte4>(element)).zyxw;
300 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500301 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500302 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500303 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500304 case VK_FORMAT_R8G8B8A8_SNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400305 c = Float4(*Pointer<SByte4>(element));
306 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500307 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
308 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500309 case VK_FORMAT_R8G8B8A8_UNORM:
310 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500311 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500312 case VK_FORMAT_R8G8B8A8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400313 c = Float4(*Pointer<Byte4>(element));
314 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500315 case VK_FORMAT_R16G16B16A16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400316 c = Float4(*Pointer<Short4>(element));
317 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500318 case VK_FORMAT_R16G16B16A16_UNORM:
319 case VK_FORMAT_R16G16B16A16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400320 c = Float4(*Pointer<UShort4>(element));
321 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500322 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400323 c = Float4(*Pointer<Int4>(element));
324 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500325 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400326 c = Float4(*Pointer<UInt4>(element));
327 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500328 case VK_FORMAT_R8G8_SINT:
329 case VK_FORMAT_R8G8_SNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400330 c.x = Float(Int(*Pointer<SByte>(element + 0)));
331 c.y = Float(Int(*Pointer<SByte>(element + 1)));
332 c.w = float(0x7F);
333 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500334 case VK_FORMAT_R8G8_UNORM:
335 case VK_FORMAT_R8G8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400336 c.x = Float(Int(*Pointer<Byte>(element + 0)));
337 c.y = Float(Int(*Pointer<Byte>(element + 1)));
338 c.w = float(0xFF);
339 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500340 case VK_FORMAT_R16G16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400341 c.x = Float(Int(*Pointer<Short>(element + 0)));
342 c.y = Float(Int(*Pointer<Short>(element + 2)));
343 c.w = float(0x7FFF);
344 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500345 case VK_FORMAT_R16G16_UNORM:
346 case VK_FORMAT_R16G16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400347 c.x = Float(Int(*Pointer<UShort>(element + 0)));
348 c.y = Float(Int(*Pointer<UShort>(element + 2)));
349 c.w = float(0xFFFF);
350 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500351 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400352 c.x = Float(*Pointer<Int>(element + 0));
353 c.y = Float(*Pointer<Int>(element + 4));
354 c.w = float(0x7FFFFFFF);
355 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500356 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400357 c.x = Float(*Pointer<UInt>(element + 0));
358 c.y = Float(*Pointer<UInt>(element + 4));
359 c.w = float(0xFFFFFFFF);
360 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500361 case VK_FORMAT_R32G32B32A32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400362 c = *Pointer<Float4>(element);
363 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500364 case VK_FORMAT_R32G32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400365 c.x = *Pointer<Float>(element + 0);
366 c.y = *Pointer<Float>(element + 4);
367 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500368 case VK_FORMAT_R32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400369 c.x = *Pointer<Float>(element);
370 break;
Ben Clayton00424c12019-03-17 17:29:30 +0000371 case VK_FORMAT_R16G16B16A16_SFLOAT:
372 c.w = Float(*Pointer<Half>(element + 6));
373 case VK_FORMAT_R16G16B16_SFLOAT:
374 c.z = Float(*Pointer<Half>(element + 4));
375 case VK_FORMAT_R16G16_SFLOAT:
376 c.y = Float(*Pointer<Half>(element + 2));
377 case VK_FORMAT_R16_SFLOAT:
378 c.x = Float(*Pointer<Half>(element));
Alexis Hetu734e2572018-12-20 14:00:49 -0500379 break;
Alexis Hetu5131ec92018-12-20 16:14:21 -0500380 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
381 // 10 (or 11) bit float formats are unsigned formats with a 5 bit exponent and a 5 (or 6) bit mantissa.
382 // Since the Half float format also has a 5 bit exponent, we can convert these formats to half by
383 // copy/pasting the bits so the the exponent bits and top mantissa bits are aligned to the half format.
384 // In this case, we have:
385 // B B B B B B B B B B G G G G G G G G G G G R R R R R R R R R R R
386 // 1st Short: |xxxxxxxxxx---------------------|
387 // 2nd Short: |xxxx---------------------xxxxxx|
388 // 3rd Short: |--------------------xxxxxxxxxxxx|
389 // These memory reads overlap, but each of them contains an entire channel, so we can read this without
390 // any int -> short conversion.
391 c.x = Float(As<Half>((*Pointer<UShort>(element + 0) & UShort(0x07FF)) << UShort(4)));
392 c.y = Float(As<Half>((*Pointer<UShort>(element + 1) & UShort(0x3FF8)) << UShort(1)));
393 c.z = Float(As<Half>((*Pointer<UShort>(element + 2) & UShort(0xFFC0)) >> UShort(1)));
394 break;
395 case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
396 // This type contains a common 5 bit exponent (E) and a 9 bit the mantissa for R, G and B.
Ben Clayton00424c12019-03-17 17:29:30 +0000397 c.x = Float(*Pointer<UInt>(element) & UInt(0x000001FF)); // R's mantissa (bits 0-8)
398 c.y = Float((*Pointer<UInt>(element) & UInt(0x0003FE00)) >> 9); // G's mantissa (bits 9-17)
Alexis Hetu5131ec92018-12-20 16:14:21 -0500399 c.z = Float((*Pointer<UInt>(element) & UInt(0x07FC0000)) >> 18); // B's mantissa (bits 18-26)
400 c *= Float4(
401 // 2^E, using the exponent (bits 27-31) and treating it as an unsigned integer value
402 Float(UInt(1) << ((*Pointer<UInt>(element) & UInt(0xF8000000)) >> 27)) *
403 // Since the 9 bit mantissa values currently stored in RGB were converted straight
404 // from int to float (in the [0, 1<<9] range instead of the [0, 1] range), they
405 // are (1 << 9) times too high.
406 // Also, the exponent has 5 bits and we compute the exponent bias of floating point
407 // formats using "2^(k-1) - 1", so, in this case, the exponent bias is 2^(5-1)-1 = 15
408 // Exponent bias (15) + number of mantissa bits per component (9) = 24
409 Float(1.0f / (1 << 24)));
410 c.w = 1.0f;
411 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500412 case VK_FORMAT_R5G6B5_UNORM_PACK16:
Nicolas Capens68a82382018-10-02 13:16:55 -0400413 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
414 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07E0)) >> UShort(5)));
415 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
416 break;
Alexis Hetu457bd9b2018-12-20 13:18:18 -0500417 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
418 c.w = Float(Int((*Pointer<UShort>(element) & UShort(0x8000)) >> UShort(15)));
419 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0x7C00)) >> UShort(10)));
420 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x03E0)) >> UShort(5)));
421 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
422 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500423 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
424 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400425 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
426 c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
427 c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
428 c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
429 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500430 case VK_FORMAT_D16_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400431 c.x = Float(Int((*Pointer<UShort>(element))));
432 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500433 case VK_FORMAT_D24_UNORM_S8_UINT:
434 case VK_FORMAT_X8_D24_UNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400435 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0xFFFFFF00)) >> 8));
436 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500437 case VK_FORMAT_D32_SFLOAT:
438 case VK_FORMAT_D32_SFLOAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400439 c.x = *Pointer<Float>(element);
440 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500441 case VK_FORMAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400442 c.x = Float(Int(*Pointer<Byte>(element)));
443 break;
444 default:
445 return false;
446 }
447
448 return true;
449 }
450
451 bool Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
452 {
453 bool writeR = state.writeRed;
454 bool writeG = state.writeGreen;
455 bool writeB = state.writeBlue;
456 bool writeA = state.writeAlpha;
457 bool writeRGBA = writeR && writeG && writeB && writeA;
458
459 switch(state.destFormat)
460 {
Alexis Hetue04d9b02019-01-16 14:42:24 -0500461 case VK_FORMAT_R4G4_UNORM_PACK8:
462 if(writeR | writeG)
463 {
464 if(!writeR)
465 {
466 *Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
467 (*Pointer<Byte>(element) & Byte(0xF0));
468 }
469 else if(!writeG)
470 {
471 *Pointer<Byte>(element) = (*Pointer<Byte>(element) & Byte(0xF)) |
472 (Byte(RoundInt(Float(c.x))) << Byte(4));
473 }
474 else
475 {
476 *Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
477 (Byte(RoundInt(Float(c.x))) << Byte(4));
478 }
479 }
480 break;
481 case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
482 if(writeR || writeG || writeB || writeA)
483 {
484 *Pointer<UShort>(element) = (writeR ? ((UShort(RoundInt(Float(c.x))) & UShort(0xF)) << UShort(12)) :
485 (*Pointer<UShort>(element) & UShort(0x000F))) |
486 (writeG ? ((UShort(RoundInt(Float(c.y))) & UShort(0xF)) << UShort(8)) :
487 (*Pointer<UShort>(element) & UShort(0x00F0))) |
488 (writeB ? ((UShort(RoundInt(Float(c.z))) & UShort(0xF)) << UShort(4)) :
489 (*Pointer<UShort>(element) & UShort(0x0F00))) |
490 (writeA ? (UShort(RoundInt(Float(c.w))) & UShort(0xF)) :
491 (*Pointer<UShort>(element) & UShort(0xF000)));
492 }
493 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500494 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
495 if(writeRGBA)
496 {
Ben Clayton00424c12019-03-17 17:29:30 +0000497 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) & Int(0xF)) |
498 UShort((RoundInt(Float(c.x)) & Int(0xF)) << 4) |
499 UShort((RoundInt(Float(c.y)) & Int(0xF)) << 8) |
500 UShort((RoundInt(Float(c.z)) & Int(0xF)) << 12);
Alexis Hetua28671d2018-12-19 17:23:26 -0500501 }
502 else
503 {
504 unsigned short mask = (writeA ? 0x000F : 0x0000) |
505 (writeR ? 0x00F0 : 0x0000) |
506 (writeG ? 0x0F00 : 0x0000) |
507 (writeB ? 0xF000 : 0x0000);
508 unsigned short unmask = ~mask;
509 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
Ben Clayton00424c12019-03-17 17:29:30 +0000510 ((UShort(RoundInt(Float(c.w)) & Int(0xF)) |
511 UShort((RoundInt(Float(c.x)) & Int(0xF)) << 4) |
512 UShort((RoundInt(Float(c.y)) & Int(0xF)) << 8) |
Alexis Hetua28671d2018-12-19 17:23:26 -0500513 UShort((RoundInt(Float(c.z)) & Int(0xF)) << 12)) & UShort(mask));
514 }
515 break;
516 case VK_FORMAT_B8G8R8A8_SRGB:
Alexis Hetudd152e12018-11-14 13:39:28 -0500517 case VK_FORMAT_B8G8R8A8_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400518 if(writeRGBA)
519 {
520 Short4 c0 = RoundShort4(c.zyxw);
521 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
522 }
523 else
524 {
525 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
526 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
527 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
528 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
529 }
530 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500531 case VK_FORMAT_B8G8R8_SNORM:
532 if(writeB) { *Pointer<SByte>(element + 0) = SByte(RoundInt(Float(c.z))); }
533 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
534 if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
535 break;
536 case VK_FORMAT_B8G8R8_UNORM:
537 case VK_FORMAT_B8G8R8_SRGB:
538 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
539 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
540 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
541 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500542 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500543 case VK_FORMAT_R8G8B8A8_UNORM:
Alexis Hetua28671d2018-12-19 17:23:26 -0500544 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500545 case VK_FORMAT_R8G8B8A8_SRGB:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500546 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
547 case VK_FORMAT_R8G8B8A8_UINT:
548 case VK_FORMAT_R8G8B8A8_USCALED:
549 case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400550 if(writeRGBA)
551 {
552 Short4 c0 = RoundShort4(c);
553 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
554 }
555 else
556 {
557 if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
558 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
559 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
560 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
561 }
562 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500563 case VK_FORMAT_R32G32B32A32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400564 if(writeRGBA)
565 {
566 *Pointer<Float4>(element) = c;
567 }
568 else
569 {
570 if(writeR) { *Pointer<Float>(element) = c.x; }
571 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
572 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
573 if(writeA) { *Pointer<Float>(element + 12) = c.w; }
574 }
575 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500576 case VK_FORMAT_R32G32B32_SFLOAT:
577 if(writeR) { *Pointer<Float>(element) = c.x; }
578 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
579 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
580 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500581 case VK_FORMAT_R32G32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400582 if(writeR && writeG)
583 {
584 *Pointer<Float2>(element) = Float2(c);
585 }
586 else
587 {
588 if(writeR) { *Pointer<Float>(element) = c.x; }
589 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
590 }
591 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500592 case VK_FORMAT_R32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400593 if(writeR) { *Pointer<Float>(element) = c.x; }
594 break;
Ben Clayton00424c12019-03-17 17:29:30 +0000595 case VK_FORMAT_R16G16B16A16_SFLOAT:
596 if(writeA) { *Pointer<Half>(element + 6) = Half(c.w); }
597 case VK_FORMAT_R16G16B16_SFLOAT:
598 if(writeB) { *Pointer<Half>(element + 4) = Half(c.z); }
599 case VK_FORMAT_R16G16_SFLOAT:
600 if(writeG) { *Pointer<Half>(element + 2) = Half(c.y); }
601 case VK_FORMAT_R16_SFLOAT:
602 if(writeR) { *Pointer<Half>(element) = Half(c.x); }
Alexis Hetu734e2572018-12-20 14:00:49 -0500603 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500604 case VK_FORMAT_B8G8R8A8_SNORM:
605 if(writeB) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.z))); }
606 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
607 if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
608 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
609 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500610 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500611 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500612 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500613 case VK_FORMAT_R8G8B8A8_SNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500614 case VK_FORMAT_R8G8B8A8_SSCALED:
615 case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400616 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
Alexis Hetue04d9b02019-01-16 14:42:24 -0500617 case VK_FORMAT_R8G8B8_SINT:
618 case VK_FORMAT_R8G8B8_SNORM:
619 case VK_FORMAT_R8G8B8_SSCALED:
620 case VK_FORMAT_R8G8B8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400621 if(writeB) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.z))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500622 case VK_FORMAT_R8G8_SINT:
623 case VK_FORMAT_R8G8_SNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500624 case VK_FORMAT_R8G8_SSCALED:
625 case VK_FORMAT_R8G8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400626 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500627 case VK_FORMAT_R8_SINT:
628 case VK_FORMAT_R8_SNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500629 case VK_FORMAT_R8_SSCALED:
630 case VK_FORMAT_R8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400631 if(writeR) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.x))); }
632 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500633 case VK_FORMAT_R8G8B8_UINT:
634 case VK_FORMAT_R8G8B8_UNORM:
635 case VK_FORMAT_R8G8B8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400636 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500637 case VK_FORMAT_R8G8_UINT:
638 case VK_FORMAT_R8G8_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500639 case VK_FORMAT_R8G8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400640 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500641 case VK_FORMAT_R8_UINT:
642 case VK_FORMAT_R8_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500643 case VK_FORMAT_R8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400644 if(writeR) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x))); }
645 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500646 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500647 case VK_FORMAT_R16G16B16A16_SNORM:
648 case VK_FORMAT_R16G16B16A16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400649 if(writeRGBA)
650 {
651 *Pointer<Short4>(element) = Short4(RoundInt(c));
652 }
653 else
654 {
655 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
656 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
657 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
658 if(writeA) { *Pointer<Short>(element + 6) = Short(RoundInt(Float(c.w))); }
659 }
660 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500661 case VK_FORMAT_R16G16B16_SINT:
662 case VK_FORMAT_R16G16B16_SNORM:
663 case VK_FORMAT_R16G16B16_SSCALED:
664 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
665 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
666 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
667 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500668 case VK_FORMAT_R16G16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500669 case VK_FORMAT_R16G16_SNORM:
670 case VK_FORMAT_R16G16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400671 if(writeR && writeG)
672 {
673 *Pointer<Short2>(element) = Short2(Short4(RoundInt(c)));
674 }
675 else
676 {
677 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
678 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
679 }
680 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500681 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500682 case VK_FORMAT_R16_SNORM:
683 case VK_FORMAT_R16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400684 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
685 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500686 case VK_FORMAT_R16G16B16A16_UINT:
687 case VK_FORMAT_R16G16B16A16_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500688 case VK_FORMAT_R16G16B16A16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400689 if(writeRGBA)
690 {
691 *Pointer<UShort4>(element) = UShort4(RoundInt(c));
692 }
693 else
694 {
695 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
696 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
697 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
698 if(writeA) { *Pointer<UShort>(element + 6) = UShort(RoundInt(Float(c.w))); }
699 }
700 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500701 case VK_FORMAT_R16G16B16_UINT:
702 case VK_FORMAT_R16G16B16_UNORM:
703 case VK_FORMAT_R16G16B16_USCALED:
704 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
705 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
706 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
707 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500708 case VK_FORMAT_R16G16_UINT:
709 case VK_FORMAT_R16G16_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500710 case VK_FORMAT_R16G16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400711 if(writeR && writeG)
712 {
713 *Pointer<UShort2>(element) = UShort2(UShort4(RoundInt(c)));
714 }
715 else
716 {
717 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
718 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
719 }
720 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500721 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500722 case VK_FORMAT_R16_UNORM:
723 case VK_FORMAT_R16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400724 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
725 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500726 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400727 if(writeRGBA)
728 {
729 *Pointer<Int4>(element) = RoundInt(c);
730 }
731 else
732 {
733 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
734 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
735 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
736 if(writeA) { *Pointer<Int>(element + 12) = RoundInt(Float(c.w)); }
737 }
738 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500739 case VK_FORMAT_R32G32B32_SINT:
740 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500741 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400742 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500743 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400744 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
745 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500746 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400747 if(writeRGBA)
748 {
749 *Pointer<UInt4>(element) = UInt4(RoundInt(c));
750 }
751 else
752 {
753 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
754 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
755 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
756 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(RoundInt(Float(c.w))); }
757 }
758 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500759 case VK_FORMAT_R32G32B32_UINT:
760 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500761 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400762 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500763 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400764 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
765 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500766 case VK_FORMAT_R5G6B5_UNORM_PACK16:
Nicolas Capens68a82382018-10-02 13:16:55 -0400767 if(writeR && writeG && writeB)
768 {
769 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.z)) |
770 (RoundInt(Float(c.y)) << Int(5)) |
771 (RoundInt(Float(c.x)) << Int(11)));
772 }
773 else
774 {
775 unsigned short mask = (writeB ? 0x001F : 0x0000) | (writeG ? 0x07E0 : 0x0000) | (writeR ? 0xF800 : 0x0000);
776 unsigned short unmask = ~mask;
777 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
778 (UShort(RoundInt(Float(c.z)) |
779 (RoundInt(Float(c.y)) << Int(5)) |
780 (RoundInt(Float(c.x)) << Int(11))) & UShort(mask));
781 }
782 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500783 case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
784 if(writeRGBA)
785 {
786 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) |
787 (RoundInt(Float(c.z)) << Int(1)) |
788 (RoundInt(Float(c.y)) << Int(6)) |
789 (RoundInt(Float(c.x)) << Int(11)));
790 }
791 else
792 {
793 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
794 (writeR ? 0x7C00 : 0x0000) |
795 (writeG ? 0x03E0 : 0x0000) |
796 (writeB ? 0x001F : 0x0000);
797 unsigned short unmask = ~mask;
798 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
799 (UShort(RoundInt(Float(c.w)) |
800 (RoundInt(Float(c.z)) << Int(1)) |
801 (RoundInt(Float(c.y)) << Int(6)) |
802 (RoundInt(Float(c.x)) << Int(11))) & UShort(mask));
803 }
804 break;
805 case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
806 if(writeRGBA)
807 {
808 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) |
809 (RoundInt(Float(c.x)) << Int(1)) |
810 (RoundInt(Float(c.y)) << Int(6)) |
811 (RoundInt(Float(c.z)) << Int(11)));
812 }
813 else
814 {
815 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
816 (writeR ? 0x7C00 : 0x0000) |
817 (writeG ? 0x03E0 : 0x0000) |
818 (writeB ? 0x001F : 0x0000);
819 unsigned short unmask = ~mask;
820 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
821 (UShort(RoundInt(Float(c.w)) |
822 (RoundInt(Float(c.x)) << Int(1)) |
823 (RoundInt(Float(c.y)) << Int(6)) |
824 (RoundInt(Float(c.z)) << Int(11))) & UShort(mask));
825 }
826 break;
Alexis Hetu457bd9b2018-12-20 13:18:18 -0500827 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
828 if(writeRGBA)
829 {
830 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.z)) |
831 (RoundInt(Float(c.y)) << Int(5)) |
832 (RoundInt(Float(c.x)) << Int(10)) |
833 (RoundInt(Float(c.w)) << Int(15)));
834 }
835 else
836 {
837 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
838 (writeR ? 0x7C00 : 0x0000) |
839 (writeG ? 0x03E0 : 0x0000) |
840 (writeB ? 0x001F : 0x0000);
841 unsigned short unmask = ~mask;
842 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
843 (UShort(RoundInt(Float(c.z)) |
844 (RoundInt(Float(c.y)) << Int(5)) |
845 (RoundInt(Float(c.x)) << Int(10)) |
846 (RoundInt(Float(c.w)) << Int(15))) & UShort(mask));
847 }
848 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500849 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
850 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500851 case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400852 if(writeRGBA)
853 {
854 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) |
855 (RoundInt(Float(c.y)) << 10) |
856 (RoundInt(Float(c.z)) << 20) |
857 (RoundInt(Float(c.w)) << 30));
858 }
859 else
860 {
861 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
862 (writeB ? 0x3FF00000 : 0x0000) |
863 (writeG ? 0x000FFC00 : 0x0000) |
864 (writeR ? 0x000003FF : 0x0000);
865 unsigned int unmask = ~mask;
866 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
867 (UInt(RoundInt(Float(c.x)) |
Alexis Hetua28671d2018-12-19 17:23:26 -0500868 (RoundInt(Float(c.y)) << 10) |
869 (RoundInt(Float(c.z)) << 20) |
870 (RoundInt(Float(c.w)) << 30)) & UInt(mask));
Nicolas Capens68a82382018-10-02 13:16:55 -0400871 }
872 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500873 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
874 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
875 case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
876 if(writeRGBA)
877 {
878 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.z)) |
879 (RoundInt(Float(c.y)) << 10) |
880 (RoundInt(Float(c.x)) << 20) |
881 (RoundInt(Float(c.w)) << 30));
882 }
883 else
884 {
885 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
886 (writeR ? 0x3FF00000 : 0x0000) |
887 (writeG ? 0x000FFC00 : 0x0000) |
888 (writeB ? 0x000003FF : 0x0000);
889 unsigned int unmask = ~mask;
890 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
891 (UInt(RoundInt(Float(c.z)) |
892 (RoundInt(Float(c.y)) << 10) |
893 (RoundInt(Float(c.x)) << 20) |
894 (RoundInt(Float(c.w)) << 30)) & UInt(mask));
895 }
896 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500897 case VK_FORMAT_D16_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400898 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x)));
899 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500900 case VK_FORMAT_D24_UNORM_S8_UINT:
901 case VK_FORMAT_X8_D24_UNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400902 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) << 8);
903 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500904 case VK_FORMAT_D32_SFLOAT:
905 case VK_FORMAT_D32_SFLOAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400906 *Pointer<Float>(element) = c.x;
907 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500908 case VK_FORMAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400909 *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
910 break;
911 default:
912 return false;
913 }
914 return true;
915 }
916
917 bool Blitter::read(Int4 &c, Pointer<Byte> element, const State &state)
918 {
919 c = Int4(0, 0, 0, 1);
920
921 switch(state.sourceFormat)
922 {
Alexis Hetua28671d2018-12-19 17:23:26 -0500923 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500924 case VK_FORMAT_R8G8B8A8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400925 c = Insert(c, Int(*Pointer<SByte>(element + 3)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500926 c = Insert(c, Int(*Pointer<SByte>(element + 2)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500927 case VK_FORMAT_R8G8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400928 c = Insert(c, Int(*Pointer<SByte>(element + 1)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500929 case VK_FORMAT_R8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400930 c = Insert(c, Int(*Pointer<SByte>(element)), 0);
931 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500932 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
933 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000003FF))), 0);
934 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10), 1);
935 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20), 2);
936 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30), 3);
937 break;
938 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500939 case VK_FORMAT_R8G8B8A8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400940 c = Insert(c, Int(*Pointer<Byte>(element + 3)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500941 c = Insert(c, Int(*Pointer<Byte>(element + 2)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500942 case VK_FORMAT_R8G8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400943 c = Insert(c, Int(*Pointer<Byte>(element + 1)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500944 case VK_FORMAT_R8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400945 c = Insert(c, Int(*Pointer<Byte>(element)), 0);
946 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500947 case VK_FORMAT_R16G16B16A16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400948 c = Insert(c, Int(*Pointer<Short>(element + 6)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500949 c = Insert(c, Int(*Pointer<Short>(element + 4)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500950 case VK_FORMAT_R16G16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400951 c = Insert(c, Int(*Pointer<Short>(element + 2)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500952 case VK_FORMAT_R16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400953 c = Insert(c, Int(*Pointer<Short>(element)), 0);
954 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500955 case VK_FORMAT_R16G16B16A16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400956 c = Insert(c, Int(*Pointer<UShort>(element + 6)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500957 c = Insert(c, Int(*Pointer<UShort>(element + 4)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500958 case VK_FORMAT_R16G16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400959 c = Insert(c, Int(*Pointer<UShort>(element + 2)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500960 case VK_FORMAT_R16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400961 c = Insert(c, Int(*Pointer<UShort>(element)), 0);
962 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500963 case VK_FORMAT_R32G32B32A32_SINT:
964 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400965 c = *Pointer<Int4>(element);
966 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500967 case VK_FORMAT_R32G32_SINT:
968 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400969 c = Insert(c, *Pointer<Int>(element + 4), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500970 case VK_FORMAT_R32_SINT:
971 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400972 c = Insert(c, *Pointer<Int>(element), 0);
973 break;
974 default:
975 return false;
976 }
977
978 return true;
979 }
980
981 bool Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
982 {
983 bool writeR = state.writeRed;
984 bool writeG = state.writeGreen;
985 bool writeB = state.writeBlue;
986 bool writeA = state.writeAlpha;
987 bool writeRGBA = writeR && writeG && writeB && writeA;
988
989 switch(state.destFormat)
990 {
Alexis Hetu6d8d3c32018-12-21 12:03:31 -0500991 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
992 c = Min(As<UInt4>(c), UInt4(0x03FF, 0x03FF, 0x03FF, 0x0003));
993 break;
994 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
995 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500996 case VK_FORMAT_R8G8B8_UINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -0500997 case VK_FORMAT_R8G8_UINT:
998 case VK_FORMAT_R8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500999 case VK_FORMAT_R8G8B8A8_USCALED:
1000 case VK_FORMAT_R8G8B8_USCALED:
1001 case VK_FORMAT_R8G8_USCALED:
1002 case VK_FORMAT_R8_USCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001003 c = Min(As<UInt4>(c), UInt4(0xFF));
1004 break;
1005 case VK_FORMAT_R16G16B16A16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001006 case VK_FORMAT_R16G16B16_UINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001007 case VK_FORMAT_R16G16_UINT:
1008 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001009 case VK_FORMAT_R16G16B16A16_USCALED:
1010 case VK_FORMAT_R16G16B16_USCALED:
1011 case VK_FORMAT_R16G16_USCALED:
1012 case VK_FORMAT_R16_USCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001013 c = Min(As<UInt4>(c), UInt4(0xFFFF));
1014 break;
1015 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1016 case VK_FORMAT_R8G8B8A8_SINT:
1017 case VK_FORMAT_R8G8_SINT:
1018 case VK_FORMAT_R8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001019 case VK_FORMAT_R8G8B8A8_SSCALED:
1020 case VK_FORMAT_R8G8B8_SSCALED:
1021 case VK_FORMAT_R8G8_SSCALED:
1022 case VK_FORMAT_R8_SSCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001023 c = Min(Max(c, Int4(-0x80)), Int4(0x7F));
1024 break;
1025 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001026 case VK_FORMAT_R16G16B16_SINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001027 case VK_FORMAT_R16G16_SINT:
1028 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001029 case VK_FORMAT_R16G16B16A16_SSCALED:
1030 case VK_FORMAT_R16G16B16_SSCALED:
1031 case VK_FORMAT_R16G16_SSCALED:
1032 case VK_FORMAT_R16_SSCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001033 c = Min(Max(c, Int4(-0x8000)), Int4(0x7FFF));
1034 break;
1035 default:
1036 break;
1037 }
1038
1039 switch(state.destFormat)
1040 {
Alexis Hetue04d9b02019-01-16 14:42:24 -05001041 case VK_FORMAT_B8G8R8A8_SINT:
1042 case VK_FORMAT_B8G8R8A8_SSCALED:
1043 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
1044 case VK_FORMAT_B8G8R8_SINT:
1045 case VK_FORMAT_B8G8R8_SRGB:
1046 case VK_FORMAT_B8G8R8_SSCALED:
1047 if(writeB) { *Pointer<SByte>(element) = SByte(Extract(c, 2)); }
1048 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
1049 if(writeR) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 0)); }
1050 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001051 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -05001052 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001053 case VK_FORMAT_R8G8B8A8_SSCALED:
1054 case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -04001055 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001056 case VK_FORMAT_R8G8B8_SINT:
1057 case VK_FORMAT_R8G8B8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001058 if(writeB) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001059 case VK_FORMAT_R8G8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001060 case VK_FORMAT_R8G8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001061 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001062 case VK_FORMAT_R8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001063 case VK_FORMAT_R8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001064 if(writeR) { *Pointer<SByte>(element) = SByte(Extract(c, 0)); }
1065 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001066 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001067 case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1068 case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
1069 case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
Alexis Hetua28671d2018-12-19 17:23:26 -05001070 if(writeRGBA)
1071 {
1072 *Pointer<UInt>(element) =
1073 UInt((Extract(c, 0)) | (Extract(c, 1) << 10) | (Extract(c, 2) << 20) | (Extract(c, 3) << 30));
1074 }
1075 else
1076 {
1077 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1078 (writeB ? 0x3FF00000 : 0x0000) |
1079 (writeG ? 0x000FFC00 : 0x0000) |
1080 (writeR ? 0x000003FF : 0x0000);
1081 unsigned int unmask = ~mask;
1082 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1083 (UInt(Extract(c, 0) | (Extract(c, 1) << 10) | (Extract(c, 2) << 20) | (Extract(c, 3) << 30)) & UInt(mask));
1084 }
1085 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001086 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1087 case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1088 case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
1089 case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
1090 if(writeRGBA)
1091 {
1092 *Pointer<UInt>(element) =
1093 UInt((Extract(c, 2)) | (Extract(c, 1) << 10) | (Extract(c, 0) << 20) | (Extract(c, 3) << 30));
1094 }
1095 else
1096 {
1097 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1098 (writeR ? 0x3FF00000 : 0x0000) |
1099 (writeG ? 0x000FFC00 : 0x0000) |
1100 (writeB ? 0x000003FF : 0x0000);
1101 unsigned int unmask = ~mask;
1102 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1103 (UInt(Extract(c, 2) | (Extract(c, 1) << 10) | (Extract(c, 0) << 20) | (Extract(c, 3) << 30)) & UInt(mask));
1104 }
1105 break;
1106 case VK_FORMAT_B8G8R8A8_UINT:
1107 case VK_FORMAT_B8G8R8A8_USCALED:
1108 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
1109 case VK_FORMAT_B8G8R8_UINT:
1110 case VK_FORMAT_B8G8R8_USCALED:
1111 if(writeB) { *Pointer<Byte>(element) = Byte(Extract(c, 2)); }
1112 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
1113 if(writeR) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 0)); }
1114 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001115 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -05001116 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001117 case VK_FORMAT_R8G8B8A8_USCALED:
1118 case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -04001119 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001120 case VK_FORMAT_R8G8B8_UINT:
1121 case VK_FORMAT_R8G8B8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001122 if(writeB) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001123 case VK_FORMAT_R8G8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001124 case VK_FORMAT_R8G8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001125 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001126 case VK_FORMAT_R8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001127 case VK_FORMAT_R8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001128 if(writeR) { *Pointer<Byte>(element) = Byte(Extract(c, 0)); }
1129 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001130 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001131 case VK_FORMAT_R16G16B16A16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001132 if(writeA) { *Pointer<Short>(element + 6) = Short(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001133 case VK_FORMAT_R16G16B16_SINT:
1134 case VK_FORMAT_R16G16B16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001135 if(writeB) { *Pointer<Short>(element + 4) = Short(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001136 case VK_FORMAT_R16G16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001137 case VK_FORMAT_R16G16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001138 if(writeG) { *Pointer<Short>(element + 2) = Short(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001139 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001140 case VK_FORMAT_R16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001141 if(writeR) { *Pointer<Short>(element) = Short(Extract(c, 0)); }
1142 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001143 case VK_FORMAT_R16G16B16A16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001144 case VK_FORMAT_R16G16B16A16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001145 if(writeA) { *Pointer<UShort>(element + 6) = UShort(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001146 case VK_FORMAT_R16G16B16_UINT:
1147 case VK_FORMAT_R16G16B16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001148 if(writeB) { *Pointer<UShort>(element + 4) = UShort(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001149 case VK_FORMAT_R16G16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001150 case VK_FORMAT_R16G16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001151 if(writeG) { *Pointer<UShort>(element + 2) = UShort(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001152 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001153 case VK_FORMAT_R16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001154 if(writeR) { *Pointer<UShort>(element) = UShort(Extract(c, 0)); }
1155 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001156 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001157 if(writeRGBA)
1158 {
1159 *Pointer<Int4>(element) = c;
1160 }
1161 else
1162 {
1163 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1164 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1165 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1166 if(writeA) { *Pointer<Int>(element + 12) = Extract(c, 3); }
1167 }
1168 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001169 case VK_FORMAT_R32G32B32_SINT:
1170 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1171 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1172 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1173 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001174 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001175 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1176 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1177 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001178 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001179 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1180 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001181 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001182 if(writeRGBA)
1183 {
1184 *Pointer<UInt4>(element) = As<UInt4>(c);
1185 }
1186 else
1187 {
1188 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1189 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
1190 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
1191 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(Extract(c, 3)); }
1192 }
1193 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001194 case VK_FORMAT_R32G32B32_UINT:
1195 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001196 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001197 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001198 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001199 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1200 break;
1201 default:
1202 return false;
1203 }
1204
1205 return true;
1206 }
1207
Nicolas Capens68a82382018-10-02 13:16:55 -04001208 bool Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
1209 {
1210 float4 scale, unscale;
1211 if(state.clearOperation &&
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001212 state.sourceFormat.isNonNormalizedInteger() &&
1213 !state.destFormat.isNonNormalizedInteger())
Nicolas Capens68a82382018-10-02 13:16:55 -04001214 {
1215 // If we're clearing a buffer from an int or uint color into a normalized color,
1216 // then the whole range of the int or uint color must be scaled between 0 and 1.
1217 switch(state.sourceFormat)
1218 {
Alexis Hetudd152e12018-11-14 13:39:28 -05001219 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001220 unscale = replicate(static_cast<float>(0x7FFFFFFF));
1221 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001222 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001223 unscale = replicate(static_cast<float>(0xFFFFFFFF));
1224 break;
1225 default:
1226 return false;
1227 }
1228 }
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001229 else if(!state.sourceFormat.getScale(unscale))
Nicolas Capens68a82382018-10-02 13:16:55 -04001230 {
1231 return false;
1232 }
1233
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001234 if(!state.destFormat.getScale(scale))
Nicolas Capens68a82382018-10-02 13:16:55 -04001235 {
1236 return false;
1237 }
1238
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001239 bool srcSRGB = state.sourceFormat.isSRGBformat();
1240 bool dstSRGB = state.destFormat.isSRGBformat();
Nicolas Capens68a82382018-10-02 13:16:55 -04001241
1242 if(state.convertSRGB && ((srcSRGB && !preScaled) || dstSRGB)) // One of the formats is sRGB encoded.
1243 {
1244 value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) : // Unapply scale
1245 Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w); // Apply unscale
1246 value = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : LinearToSRGB(value);
1247 value *= Float4(scale.x, scale.y, scale.z, scale.w); // Apply scale
1248 }
1249 else if(unscale != scale)
1250 {
1251 value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
1252 }
1253
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001254 if(state.sourceFormat.isFloatFormat() && !state.destFormat.isFloatFormat())
Nicolas Capens68a82382018-10-02 13:16:55 -04001255 {
1256 value = Min(value, Float4(scale.x, scale.y, scale.z, scale.w));
1257
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001258 value = Max(value, Float4(state.destFormat.isUnsignedComponent(0) ? 0.0f : -scale.x,
1259 state.destFormat.isUnsignedComponent(1) ? 0.0f : -scale.y,
1260 state.destFormat.isUnsignedComponent(2) ? 0.0f : -scale.z,
1261 state.destFormat.isUnsignedComponent(3) ? 0.0f : -scale.w));
Nicolas Capens68a82382018-10-02 13:16:55 -04001262 }
1263
1264 return true;
1265 }
1266
1267 Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout)
1268 {
1269 if(!quadLayout)
1270 {
1271 return y * pitchB + x * bytes;
1272 }
1273 else
1274 {
1275 // (x & ~1) * 2 + (x & 1) == (x - (x & 1)) * 2 + (x & 1) == x * 2 - (x & 1) * 2 + (x & 1) == x * 2 - (x & 1)
1276 return (y & Int(~1)) * pitchB +
1277 ((y & Int(1)) * 2 + x * 2 - (x & Int(1))) * bytes;
1278 }
1279 }
1280
1281 Float4 Blitter::LinearToSRGB(Float4 &c)
1282 {
1283 Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
1284 Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
1285
1286 Float4 s = c;
1287 s.xyz = Max(lc, ec);
1288
1289 return s;
1290 }
1291
1292 Float4 Blitter::sRGBtoLinear(Float4 &c)
1293 {
1294 Float4 lc = c * Float4(1.0f / 12.92f);
1295 Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
1296
1297 Int4 linear = CmpLT(c, Float4(0.04045f));
1298
1299 Float4 s = c;
Ben Clayton5e9441a2019-05-24 07:43:42 +01001300 s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec))); // TODO: IfThenElse()
Nicolas Capens68a82382018-10-02 13:16:55 -04001301
1302 return s;
1303 }
1304
1305 Routine *Blitter::generate(const State &state)
1306 {
1307 Function<Void(Pointer<Byte>)> function;
1308 {
1309 Pointer<Byte> blit(function.Arg<0>());
1310
1311 Pointer<Byte> source = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,source));
1312 Pointer<Byte> dest = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,dest));
1313 Int sPitchB = *Pointer<Int>(blit + OFFSET(BlitData,sPitchB));
1314 Int dPitchB = *Pointer<Int>(blit + OFFSET(BlitData,dPitchB));
1315
1316 Float x0 = *Pointer<Float>(blit + OFFSET(BlitData,x0));
1317 Float y0 = *Pointer<Float>(blit + OFFSET(BlitData,y0));
1318 Float w = *Pointer<Float>(blit + OFFSET(BlitData,w));
1319 Float h = *Pointer<Float>(blit + OFFSET(BlitData,h));
1320
1321 Int x0d = *Pointer<Int>(blit + OFFSET(BlitData,x0d));
1322 Int x1d = *Pointer<Int>(blit + OFFSET(BlitData,x1d));
1323 Int y0d = *Pointer<Int>(blit + OFFSET(BlitData,y0d));
1324 Int y1d = *Pointer<Int>(blit + OFFSET(BlitData,y1d));
1325
1326 Int sWidth = *Pointer<Int>(blit + OFFSET(BlitData,sWidth));
1327 Int sHeight = *Pointer<Int>(blit + OFFSET(BlitData,sHeight));
1328
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001329 bool intSrc = state.sourceFormat.isNonNormalizedInteger();
1330 bool intDst = state.destFormat.isNonNormalizedInteger();
Nicolas Capens68a82382018-10-02 13:16:55 -04001331 bool intBoth = intSrc && intDst;
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001332 bool srcQuadLayout = state.sourceFormat.hasQuadLayout();
1333 bool dstQuadLayout = state.destFormat.hasQuadLayout();
1334 int srcBytes = state.sourceFormat.bytes();
1335 int dstBytes = state.destFormat.bytes();
Nicolas Capens68a82382018-10-02 13:16:55 -04001336
1337 bool hasConstantColorI = false;
1338 Int4 constantColorI;
1339 bool hasConstantColorF = false;
1340 Float4 constantColorF;
1341 if(state.clearOperation)
1342 {
1343 if(intBoth) // Integer types
1344 {
1345 if(!read(constantColorI, source, state))
1346 {
1347 return nullptr;
1348 }
1349 hasConstantColorI = true;
1350 }
1351 else
1352 {
1353 if(!read(constantColorF, source, state))
1354 {
1355 return nullptr;
1356 }
1357 hasConstantColorF = true;
1358
1359 if(!ApplyScaleAndClamp(constantColorF, state))
1360 {
1361 return nullptr;
1362 }
1363 }
1364 }
1365
1366 For(Int j = y0d, j < y1d, j++)
1367 {
1368 Float y = state.clearOperation ? RValue<Float>(y0) : y0 + Float(j) * h;
1369 Pointer<Byte> destLine = dest + (dstQuadLayout ? j & Int(~1) : RValue<Int>(j)) * dPitchB;
1370
1371 For(Int i = x0d, i < x1d, i++)
1372 {
1373 Float x = state.clearOperation ? RValue<Float>(x0) : x0 + Float(i) * w;
1374 Pointer<Byte> d = destLine + (dstQuadLayout ? (((j & Int(1)) << 1) + (i * 2) - (i & Int(1))) : RValue<Int>(i)) * dstBytes;
1375
1376 if(hasConstantColorI)
1377 {
1378 if(!write(constantColorI, d, state))
1379 {
1380 return nullptr;
1381 }
1382 }
1383 else if(hasConstantColorF)
1384 {
1385 for(int s = 0; s < state.destSamples; s++)
1386 {
1387 if(!write(constantColorF, d, state))
1388 {
1389 return nullptr;
1390 }
1391
1392 d += *Pointer<Int>(blit + OFFSET(BlitData, dSliceB));
1393 }
1394 }
1395 else if(intBoth) // Integer types do not support filtering
1396 {
1397 Int4 color; // When both formats are true integer types, we don't go to float to avoid losing precision
1398 Int X = Int(x);
1399 Int Y = Int(y);
1400
1401 if(state.clampToEdge)
1402 {
1403 X = Clamp(X, 0, sWidth - 1);
1404 Y = Clamp(Y, 0, sHeight - 1);
1405 }
1406
1407 Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1408
1409 if(!read(color, s, state))
1410 {
1411 return nullptr;
1412 }
1413
1414 if(!write(color, d, state))
1415 {
1416 return nullptr;
1417 }
1418 }
1419 else
1420 {
1421 Float4 color;
1422
1423 bool preScaled = false;
1424 if(!state.filter || intSrc)
1425 {
1426 Int X = Int(x);
1427 Int Y = Int(y);
1428
1429 if(state.clampToEdge)
1430 {
1431 X = Clamp(X, 0, sWidth - 1);
1432 Y = Clamp(Y, 0, sHeight - 1);
1433 }
1434
1435 Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1436
1437 if(!read(color, s, state))
1438 {
1439 return nullptr;
1440 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001441
1442 if(state.srcSamples > 1) // Resolve multisampled source
1443 {
Alexis Hetua4308132019-06-13 09:55:26 -04001444 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1445 {
1446 if(!ApplyScaleAndClamp(color, state)) return nullptr;
1447 preScaled = true;
1448 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001449 Float4 accum = color;
1450 for(int i = 1; i < state.srcSamples; i++)
1451 {
1452 s += *Pointer<Int>(blit + OFFSET(BlitData, sSliceB));
1453 if(!read(color, s, state))
1454 {
1455 return nullptr;
1456 }
Alexis Hetu3f80dad2019-05-22 18:23:47 -04001457 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1458 {
1459 if(!ApplyScaleAndClamp(color, state)) return nullptr;
1460 preScaled = true;
1461 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001462 accum += color;
1463 }
1464 color = accum * Float4(1.0f / static_cast<float>(state.srcSamples));
1465 }
Nicolas Capens68a82382018-10-02 13:16:55 -04001466 }
1467 else // Bilinear filtering
1468 {
1469 Float X = x;
1470 Float Y = y;
1471
1472 if(state.clampToEdge)
1473 {
1474 X = Min(Max(x, 0.5f), Float(sWidth) - 0.5f);
1475 Y = Min(Max(y, 0.5f), Float(sHeight) - 0.5f);
1476 }
1477
1478 Float x0 = X - 0.5f;
1479 Float y0 = Y - 0.5f;
1480
1481 Int X0 = Max(Int(x0), 0);
1482 Int Y0 = Max(Int(y0), 0);
1483
1484 Int X1 = X0 + 1;
1485 Int Y1 = Y0 + 1;
1486 X1 = IfThenElse(X1 >= sWidth, X0, X1);
1487 Y1 = IfThenElse(Y1 >= sHeight, Y0, Y1);
1488
1489 Pointer<Byte> s00 = source + ComputeOffset(X0, Y0, sPitchB, srcBytes, srcQuadLayout);
1490 Pointer<Byte> s01 = source + ComputeOffset(X1, Y0, sPitchB, srcBytes, srcQuadLayout);
1491 Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, sPitchB, srcBytes, srcQuadLayout);
1492 Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, sPitchB, srcBytes, srcQuadLayout);
1493
1494 Float4 c00; if(!read(c00, s00, state)) return nullptr;
1495 Float4 c01; if(!read(c01, s01, state)) return nullptr;
1496 Float4 c10; if(!read(c10, s10, state)) return nullptr;
1497 Float4 c11; if(!read(c11, s11, state)) return nullptr;
1498
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001499 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
Nicolas Capens68a82382018-10-02 13:16:55 -04001500 {
1501 if(!ApplyScaleAndClamp(c00, state)) return nullptr;
1502 if(!ApplyScaleAndClamp(c01, state)) return nullptr;
1503 if(!ApplyScaleAndClamp(c10, state)) return nullptr;
1504 if(!ApplyScaleAndClamp(c11, state)) return nullptr;
1505 preScaled = true;
1506 }
1507
1508 Float4 fx = Float4(x0 - Float(X0));
1509 Float4 fy = Float4(y0 - Float(Y0));
1510 Float4 ix = Float4(1.0f) - fx;
1511 Float4 iy = Float4(1.0f) - fy;
1512
1513 color = (c00 * ix + c01 * fx) * iy +
1514 (c10 * ix + c11 * fx) * fy;
1515 }
1516
1517 if(!ApplyScaleAndClamp(color, state, preScaled))
1518 {
1519 return nullptr;
1520 }
1521
1522 for(int s = 0; s < state.destSamples; s++)
1523 {
1524 if(!write(color, d, state))
1525 {
1526 return nullptr;
1527 }
1528
1529 d += *Pointer<Int>(blit + OFFSET(BlitData,dSliceB));
1530 }
1531 }
1532 }
1533 }
1534 }
1535
Chris Forbes878d4b02019-01-21 10:48:35 -08001536 return function("BlitRoutine");
Nicolas Capens68a82382018-10-02 13:16:55 -04001537 }
1538
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001539 Routine *Blitter::getBlitRoutine(const State &state)
Alexis Hetu33642272019-03-01 11:55:59 -05001540 {
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001541 std::unique_lock<std::mutex> lock(blitMutex);
1542 Routine *blitRoutine = blitCache.query(state);
Alexis Hetu33642272019-03-01 11:55:59 -05001543
1544 if(!blitRoutine)
1545 {
1546 blitRoutine = generate(state);
1547
1548 if(!blitRoutine)
1549 {
Ben Clayton00424c12019-03-17 17:29:30 +00001550 UNIMPLEMENTED("blitRoutine");
Alexis Hetu33642272019-03-01 11:55:59 -05001551 return nullptr;
1552 }
1553
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001554 blitCache.add(state, blitRoutine);
Alexis Hetu33642272019-03-01 11:55:59 -05001555 }
1556
Alexis Hetu33642272019-03-01 11:55:59 -05001557 return blitRoutine;
1558 }
1559
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001560 Routine *Blitter::getCornerUpdateRoutine(const State &state)
1561 {
1562 std::unique_lock<std::mutex> lock(cornerUpdateMutex);
1563 Routine *cornerUpdateRoutine = cornerUpdateCache.query(state);
1564
1565 if(!cornerUpdateRoutine)
1566 {
1567 cornerUpdateRoutine = generateCornerUpdate(state);
1568
1569 if(!cornerUpdateRoutine)
1570 {
1571 UNIMPLEMENTED("cornerUpdateRoutine");
1572 return nullptr;
1573 }
1574
1575 cornerUpdateCache.add(state, cornerUpdateRoutine);
1576 }
1577
1578 return cornerUpdateRoutine;
1579 }
1580
Chris Forbes529eda32019-05-08 10:27:05 -07001581 void Blitter::blitToBuffer(const vk::Image *src, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *dst, int bufferRowPitch, int bufferSlicePitch)
1582 {
1583 auto aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
1584 auto format = src->getFormat(aspect);
1585 State state(format, format.getNonQuadLayoutFormat(), VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
1586 {false, false});
1587
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001588 Routine *blitRoutine = getBlitRoutine(state);
Chris Forbes529eda32019-05-08 10:27:05 -07001589 if(!blitRoutine)
1590 {
1591 return;
1592 }
1593
1594 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1595
1596 BlitData data =
1597 {
1598 nullptr, // source
1599 dst, // dest
1600 src->rowPitchBytes(aspect, subresource.mipLevel), // sPitchB
1601 bufferRowPitch, // dPitchB
1602 src->slicePitchBytes(aspect, subresource.mipLevel), // sSliceB
1603 bufferSlicePitch, // dSliceB
1604
1605 0, 0, 1, 1,
1606
1607 0, // y0d
1608 static_cast<int>(extent.height), // y1d
1609 0, // x0d
1610 static_cast<int>(extent.width), // x1d
1611
1612 static_cast<int>(extent.width), // sWidth
1613 static_cast<int>(extent.height) // sHeight;
1614 };
1615
1616 VkOffset3D srcOffset = { 0, 0, offset.z };
1617
1618 VkImageSubresourceLayers srcSubresLayers = subresource;
1619 srcSubresLayers.layerCount = 1;
1620
1621 VkImageSubresourceRange srcSubresRange =
1622 {
1623 subresource.aspectMask,
1624 subresource.mipLevel,
1625 1,
1626 subresource.baseArrayLayer,
1627 subresource.layerCount
1628 };
1629
1630 uint32_t lastLayer = src->getLastLayerIndex(srcSubresRange);
1631
1632 for(; srcSubresLayers.baseArrayLayer <= lastLayer; srcSubresLayers.baseArrayLayer++)
1633 {
1634 srcOffset.z = offset.z;
1635
1636 for(auto i = 0u; i < extent.depth; i++)
1637 {
1638 data.source = src->getTexelPointer(srcOffset, srcSubresLayers);
1639 ASSERT(data.source < src->end());
1640 blitFunction(&data);
1641 srcOffset.z++;
1642 data.dest = (dst += bufferSlicePitch);
1643 }
1644 }
1645 }
1646
1647 void Blitter::blitFromBuffer(const vk::Image *dst, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *src, int bufferRowPitch, int bufferSlicePitch)
1648 {
1649 auto aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
1650 auto format = dst->getFormat(aspect);
1651 State state(format.getNonQuadLayoutFormat(), format, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
1652 {false, false});
1653
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001654 Routine *blitRoutine = getBlitRoutine(state);
Chris Forbes529eda32019-05-08 10:27:05 -07001655 if(!blitRoutine)
1656 {
1657 return;
1658 }
1659
1660 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1661
1662 BlitData data =
1663 {
1664 src, // source
1665 nullptr, // dest
1666 bufferRowPitch, // sPitchB
1667 dst->rowPitchBytes(aspect, subresource.mipLevel), // dPitchB
1668 bufferSlicePitch, // sSliceB
1669 dst->slicePitchBytes(aspect, subresource.mipLevel), // dSliceB
1670
1671 0, 0, 1, 1,
1672
1673 offset.y, // y0d
1674 static_cast<int>(offset.y + extent.height), // y1d
1675 offset.x, // x0d
1676 static_cast<int>(offset.x + extent.width), // x1d
1677
1678 static_cast<int>(extent.width), // sWidth
1679 static_cast<int>(extent.height) // sHeight;
1680 };
1681
1682 VkOffset3D dstOffset = { 0, 0, offset.z };
1683
1684 VkImageSubresourceLayers dstSubresLayers = subresource;
1685 dstSubresLayers.layerCount = 1;
1686
1687 VkImageSubresourceRange dstSubresRange =
1688 {
1689 subresource.aspectMask,
1690 subresource.mipLevel,
1691 1,
1692 subresource.baseArrayLayer,
1693 subresource.layerCount
1694 };
1695
1696 uint32_t lastLayer = dst->getLastLayerIndex(dstSubresRange);
1697
1698 for(; dstSubresLayers.baseArrayLayer <= lastLayer; dstSubresLayers.baseArrayLayer++)
1699 {
1700 dstOffset.z = offset.z;
1701
1702 for(auto i = 0u; i < extent.depth; i++)
1703 {
1704 data.dest = dst->getTexelPointer(dstOffset, dstSubresLayers);
1705 ASSERT(data.dest < dst->end());
1706 blitFunction(&data);
1707 dstOffset.z++;
1708 data.source = (src += bufferSlicePitch);
1709 }
1710 }
1711 }
1712
Alexis Hetuac873342019-04-17 15:59:03 -04001713 void Blitter::blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter)
Alexis Hetu33642272019-03-01 11:55:59 -05001714 {
1715 if(dst->getFormat() == VK_FORMAT_UNDEFINED)
1716 {
1717 return;
1718 }
1719
Alexis Hetu377077a2019-03-14 15:10:51 -04001720 if((region.srcSubresource.layerCount != region.dstSubresource.layerCount) ||
Alexis Hetu33642272019-03-01 11:55:59 -05001721 (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask))
1722 {
Ben Clayton00424c12019-03-17 17:29:30 +00001723 UNIMPLEMENTED("region");
Alexis Hetu33642272019-03-01 11:55:59 -05001724 }
1725
1726 if(region.dstOffsets[0].x > region.dstOffsets[1].x)
1727 {
Nicolas Capensb8c63932019-03-19 01:52:40 -04001728 std::swap(region.srcOffsets[0].x, region.srcOffsets[1].x);
1729 std::swap(region.dstOffsets[0].x, region.dstOffsets[1].x);
Alexis Hetu33642272019-03-01 11:55:59 -05001730 }
1731
1732 if(region.dstOffsets[0].y > region.dstOffsets[1].y)
1733 {
Nicolas Capensb8c63932019-03-19 01:52:40 -04001734 std::swap(region.srcOffsets[0].y, region.srcOffsets[1].y);
1735 std::swap(region.dstOffsets[0].y, region.dstOffsets[1].y);
Alexis Hetu33642272019-03-01 11:55:59 -05001736 }
1737
Nicolas Capensba873302019-05-16 11:25:27 -04001738 VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask);
1739 VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask);
1740 VkExtent3D srcExtent = src->getMipLevelExtent(srcAspect, region.srcSubresource.mipLevel);
Alexis Hetu33642272019-03-01 11:55:59 -05001741
1742 int32_t numSlices = (region.srcOffsets[1].z - region.srcOffsets[0].z);
1743 ASSERT(numSlices == (region.dstOffsets[1].z - region.dstOffsets[0].z));
1744
Alexis Hetue24bc662019-03-21 18:04:29 -04001745 float widthRatio = static_cast<float>(region.srcOffsets[1].x - region.srcOffsets[0].x) /
1746 static_cast<float>(region.dstOffsets[1].x - region.dstOffsets[0].x);
1747 float heightRatio = static_cast<float>(region.srcOffsets[1].y - region.srcOffsets[0].y) /
1748 static_cast<float>(region.dstOffsets[1].y - region.dstOffsets[0].y);
1749 float x0 = region.srcOffsets[0].x + (0.5f - region.dstOffsets[0].x) * widthRatio;
1750 float y0 = region.srcOffsets[0].y + (0.5f - region.dstOffsets[0].y) * heightRatio;
1751
1752 bool doFilter = (filter != VK_FILTER_NEAREST);
Alexis Hetu54ec7592019-03-20 14:37:16 -04001753 State state(src->getFormat(srcAspect), dst->getFormat(dstAspect), src->getSampleCountFlagBits(), dst->getSampleCountFlagBits(),
Alexis Hetu3f80dad2019-05-22 18:23:47 -04001754 { doFilter, doFilter || (src->getSampleCountFlagBits() > 1) });
Alexis Hetu33642272019-03-01 11:55:59 -05001755 state.clampToEdge = (region.srcOffsets[0].x < 0) ||
1756 (region.srcOffsets[0].y < 0) ||
1757 (static_cast<uint32_t>(region.srcOffsets[1].x) > srcExtent.width) ||
Alexis Hetue24bc662019-03-21 18:04:29 -04001758 (static_cast<uint32_t>(region.srcOffsets[1].y) > srcExtent.height) ||
1759 (doFilter && ((x0 < 0.5f) || (y0 < 0.5f)));
Alexis Hetu33642272019-03-01 11:55:59 -05001760
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001761 Routine *blitRoutine = getBlitRoutine(state);
Alexis Hetu33642272019-03-01 11:55:59 -05001762 if(!blitRoutine)
1763 {
1764 return;
1765 }
1766
1767 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1768
Alexis Hetue24bc662019-03-21 18:04:29 -04001769 BlitData data =
1770 {
1771 nullptr, // source
1772 nullptr, // dest
1773 src->rowPitchBytes(srcAspect, region.srcSubresource.mipLevel), // sPitchB
1774 dst->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel), // dPitchB
Alexis Hetu54ec7592019-03-20 14:37:16 -04001775 src->slicePitchBytes(srcAspect, region.srcSubresource.mipLevel), // sSliceB
Alexis Hetue24bc662019-03-21 18:04:29 -04001776 dst->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel), // dSliceB
Alexis Hetu33642272019-03-01 11:55:59 -05001777
Alexis Hetue24bc662019-03-21 18:04:29 -04001778 x0,
1779 y0,
1780 widthRatio,
1781 heightRatio,
Alexis Hetu33642272019-03-01 11:55:59 -05001782
Alexis Hetue24bc662019-03-21 18:04:29 -04001783 region.dstOffsets[0].y, // y0d
1784 region.dstOffsets[1].y, // y1d
1785 region.dstOffsets[0].x, // x0d
1786 region.dstOffsets[1].x, // x1d
Alexis Hetu33642272019-03-01 11:55:59 -05001787
Alexis Hetue24bc662019-03-21 18:04:29 -04001788 static_cast<int>(srcExtent.width), // sWidth
1789 static_cast<int>(srcExtent.height) // sHeight;
1790 };
Alexis Hetu33642272019-03-01 11:55:59 -05001791
1792 VkOffset3D srcOffset = { 0, 0, region.srcOffsets[0].z };
1793 VkOffset3D dstOffset = { 0, 0, region.dstOffsets[0].z };
1794
Alexis Hetu377077a2019-03-14 15:10:51 -04001795 VkImageSubresourceLayers srcSubresLayers =
Alexis Hetu33642272019-03-01 11:55:59 -05001796 {
Alexis Hetu377077a2019-03-14 15:10:51 -04001797 region.srcSubresource.aspectMask,
1798 region.srcSubresource.mipLevel,
1799 region.srcSubresource.baseArrayLayer,
1800 1
1801 };
1802
1803 VkImageSubresourceLayers dstSubresLayers =
1804 {
1805 region.dstSubresource.aspectMask,
1806 region.dstSubresource.mipLevel,
1807 region.dstSubresource.baseArrayLayer,
1808 1
1809 };
1810
1811 VkImageSubresourceRange srcSubresRange =
1812 {
1813 region.srcSubresource.aspectMask,
1814 region.srcSubresource.mipLevel,
1815 1,
1816 region.srcSubresource.baseArrayLayer,
1817 region.srcSubresource.layerCount
1818 };
1819
1820 uint32_t lastLayer = src->getLastLayerIndex(srcSubresRange);
1821
1822 for(; srcSubresLayers.baseArrayLayer <= lastLayer; srcSubresLayers.baseArrayLayer++, dstSubresLayers.baseArrayLayer++)
1823 {
1824 srcOffset.z = region.srcOffsets[0].z;
1825 dstOffset.z = region.dstOffsets[0].z;
1826
1827 for(int i = 0; i < numSlices; i++)
1828 {
1829 data.source = src->getTexelPointer(srcOffset, srcSubresLayers);
1830 data.dest = dst->getTexelPointer(dstOffset, dstSubresLayers);
1831
1832 ASSERT(data.source < src->end());
1833 ASSERT(data.dest < dst->end());
1834
1835 blitFunction(&data);
1836 srcOffset.z++;
1837 dstOffset.z++;
1838 }
Alexis Hetu33642272019-03-01 11:55:59 -05001839 }
1840 }
Alexis Hetub317d962019-04-29 14:07:31 -04001841
1842 void Blitter::computeCubeCorner(Pointer<Byte>& layer, Int& x0, Int& x1, Int& y0, Int& y1, Int& pitchB, const State& state)
1843 {
1844 int bytes = state.sourceFormat.bytes();
1845 bool quadLayout = state.sourceFormat.hasQuadLayout();
1846
1847 Float4 c0;
1848 read(c0, layer + ComputeOffset(x0, y1, pitchB, bytes, quadLayout), state);
1849 Float4 c1;
1850 read(c1, layer + ComputeOffset(x1, y0, pitchB, bytes, quadLayout), state);
1851 c0 += c1;
1852 read(c1, layer + ComputeOffset(x1, y1, pitchB, bytes, quadLayout), state);
1853 c0 += c1;
1854 c0 *= Float4(1.0f / 3.0f);
1855 write(c0, layer + ComputeOffset(x0, y0, pitchB, bytes, quadLayout), state);
1856 }
1857
1858 Routine *Blitter::generateCornerUpdate(const State& state)
1859 {
1860 // Reading and writing from/to the same image
1861 ASSERT(state.sourceFormat == state.destFormat);
1862 ASSERT(state.srcSamples == state.destSamples);
1863
1864 if(state.srcSamples != 1)
1865 {
1866 UNIMPLEMENTED("state.srcSamples %d", state.srcSamples);
1867 }
1868
1869 Function<Void(Pointer<Byte>)> function;
1870 {
1871 Pointer<Byte> blit(function.Arg<0>());
1872
1873 Pointer<Byte> layers = *Pointer<Pointer<Byte>>(blit + OFFSET(CubeBorderData, layers));
1874 Int pitchB = *Pointer<Int>(blit + OFFSET(CubeBorderData, pitchB));
1875 UInt layerSize = *Pointer<Int>(blit + OFFSET(CubeBorderData, layerSize));
1876 UInt dim = *Pointer<Int>(blit + OFFSET(CubeBorderData, dim));
1877
1878 // Low Border, Low Pixel, High Border, High Pixel
1879 Int LB(-1), LP(0), HB(dim), HP(dim-1);
1880
Nicolas Capensbb575d42019-05-31 15:36:59 -04001881 for(int face = 0; face < 6; face++)
Alexis Hetub317d962019-04-29 14:07:31 -04001882 {
1883 computeCubeCorner(layers, LB, LP, LB, LP, pitchB, state);
1884 computeCubeCorner(layers, LB, LP, HB, HP, pitchB, state);
1885 computeCubeCorner(layers, HB, HP, LB, LP, pitchB, state);
1886 computeCubeCorner(layers, HB, HP, HB, HP, pitchB, state);
1887 layers = layers + layerSize;
1888 }
1889 }
1890
1891 return function("BlitRoutine");
1892 }
1893
1894 void Blitter::updateBorders(vk::Image* image, const VkImageSubresourceLayers& subresourceLayers)
1895 {
1896 if(image->getArrayLayers() < (subresourceLayers.baseArrayLayer + 6))
1897 {
1898 UNIMPLEMENTED("image->getArrayLayers() %d, baseArrayLayer %d",
1899 image->getArrayLayers(), subresourceLayers.baseArrayLayer);
1900 }
1901
1902 // From Vulkan 1.1 spec, section 11.5. Image Views:
1903 // "For cube and cube array image views, the layers of the image view starting
1904 // at baseArrayLayer correspond to faces in the order +X, -X, +Y, -Y, +Z, -Z."
1905 VkImageSubresourceLayers posX = subresourceLayers;
1906 posX.layerCount = 1;
1907 VkImageSubresourceLayers negX = posX;
1908 negX.baseArrayLayer++;
1909 VkImageSubresourceLayers posY = negX;
1910 posY.baseArrayLayer++;
1911 VkImageSubresourceLayers negY = posY;
1912 negY.baseArrayLayer++;
1913 VkImageSubresourceLayers posZ = negY;
1914 posZ.baseArrayLayer++;
1915 VkImageSubresourceLayers negZ = posZ;
1916 negZ.baseArrayLayer++;
1917
1918 // Copy top / bottom
1919 copyCubeEdge(image, posX, BOTTOM, negY, RIGHT);
1920 copyCubeEdge(image, posY, BOTTOM, posZ, TOP);
1921 copyCubeEdge(image, posZ, BOTTOM, negY, TOP);
1922 copyCubeEdge(image, negX, BOTTOM, negY, LEFT);
1923 copyCubeEdge(image, negY, BOTTOM, negZ, BOTTOM);
1924 copyCubeEdge(image, negZ, BOTTOM, negY, BOTTOM);
1925
1926 copyCubeEdge(image, posX, TOP, posY, RIGHT);
1927 copyCubeEdge(image, posY, TOP, negZ, TOP);
1928 copyCubeEdge(image, posZ, TOP, posY, BOTTOM);
1929 copyCubeEdge(image, negX, TOP, posY, LEFT);
1930 copyCubeEdge(image, negY, TOP, posZ, BOTTOM);
1931 copyCubeEdge(image, negZ, TOP, posY, TOP);
1932
1933 // Copy left / right
1934 copyCubeEdge(image, posX, RIGHT, negZ, LEFT);
1935 copyCubeEdge(image, posY, RIGHT, posX, TOP);
1936 copyCubeEdge(image, posZ, RIGHT, posX, LEFT);
1937 copyCubeEdge(image, negX, RIGHT, posZ, LEFT);
1938 copyCubeEdge(image, negY, RIGHT, posX, BOTTOM);
1939 copyCubeEdge(image, negZ, RIGHT, negX, LEFT);
1940
1941 copyCubeEdge(image, posX, LEFT, posZ, RIGHT);
1942 copyCubeEdge(image, posY, LEFT, negX, TOP);
1943 copyCubeEdge(image, posZ, LEFT, negX, RIGHT);
1944 copyCubeEdge(image, negX, LEFT, negZ, RIGHT);
1945 copyCubeEdge(image, negY, LEFT, negX, BOTTOM);
1946 copyCubeEdge(image, negZ, LEFT, posX, RIGHT);
1947
1948 // Compute corner colors
1949 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceLayers.aspectMask);
1950 vk::Format format = image->getFormat(aspect);
1951 VkSampleCountFlagBits samples = image->getSampleCountFlagBits();
1952 State state(format, format, samples, samples, { 0xF });
1953
1954 if(samples != VK_SAMPLE_COUNT_1_BIT)
1955 {
1956 UNIMPLEMENTED("Multi-sampled cube: %d samples", static_cast<int>(samples));
1957 }
1958
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001959 Routine *cornerUpdateRoutine = getCornerUpdateRoutine(state);
Alexis Hetub317d962019-04-29 14:07:31 -04001960 if(!cornerUpdateRoutine)
1961 {
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001962 return;
Alexis Hetub317d962019-04-29 14:07:31 -04001963 }
1964
Alexis Hetub317d962019-04-29 14:07:31 -04001965 void(*cornerUpdateFunction)(const CubeBorderData *data) = (void(*)(const CubeBorderData*))cornerUpdateRoutine->getEntry();
1966
Nicolas Capensba873302019-05-16 11:25:27 -04001967 VkExtent3D extent = image->getMipLevelExtent(aspect, subresourceLayers.mipLevel);
Alexis Hetub317d962019-04-29 14:07:31 -04001968 CubeBorderData data =
1969 {
1970 image->getTexelPointer({ 0, 0, 0 }, posX),
1971 image->rowPitchBytes(aspect, subresourceLayers.mipLevel),
1972 static_cast<uint32_t>(image->getLayerSize(aspect)),
1973 extent.width
1974 };
1975 cornerUpdateFunction(&data);
1976 }
1977
1978 void Blitter::copyCubeEdge(vk::Image* image,
1979 const VkImageSubresourceLayers& dstSubresourceLayers, Edge dstEdge,
1980 const VkImageSubresourceLayers& srcSubresourceLayers, Edge srcEdge)
1981 {
1982 ASSERT(srcSubresourceLayers.aspectMask == dstSubresourceLayers.aspectMask);
1983 ASSERT(srcSubresourceLayers.mipLevel == dstSubresourceLayers.mipLevel);
1984 ASSERT(srcSubresourceLayers.baseArrayLayer != dstSubresourceLayers.baseArrayLayer);
1985 ASSERT(srcSubresourceLayers.layerCount == 1);
1986 ASSERT(dstSubresourceLayers.layerCount == 1);
1987
1988 // Figure out if the edges to be copied in reverse order respectively from one another
1989 // The copy should be reversed whenever the same edges are contiguous or if we're
1990 // copying top <-> right or bottom <-> left. This is explained by the layout, which is:
1991 //
1992 // | +y |
1993 // | -x | +z | +x | -z |
1994 // | -y |
1995
1996 bool reverse = (srcEdge == dstEdge) ||
1997 ((srcEdge == TOP) && (dstEdge == RIGHT)) ||
1998 ((srcEdge == RIGHT) && (dstEdge == TOP)) ||
1999 ((srcEdge == BOTTOM) && (dstEdge == LEFT)) ||
2000 ((srcEdge == LEFT) && (dstEdge == BOTTOM));
2001
2002 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(srcSubresourceLayers.aspectMask);
2003 int bytes = image->getFormat(aspect).bytes();
2004 int pitchB = image->rowPitchBytes(aspect, srcSubresourceLayers.mipLevel);
2005
Nicolas Capensba873302019-05-16 11:25:27 -04002006 VkExtent3D extent = image->getMipLevelExtent(aspect, srcSubresourceLayers.mipLevel);
Alexis Hetub317d962019-04-29 14:07:31 -04002007 int w = extent.width;
2008 int h = extent.height;
2009 if(w != h)
2010 {
2011 UNIMPLEMENTED("Cube doesn't have square faces : (%d, %d)", w, h);
2012 }
2013
2014 // Src is expressed in the regular [0, width-1], [0, height-1] space
2015 bool srcHorizontal = ((srcEdge == TOP) || (srcEdge == BOTTOM));
2016 int srcDelta = srcHorizontal ? bytes : pitchB;
2017 VkOffset3D srcOffset = { (srcEdge == RIGHT) ? (w - 1) : 0, (srcEdge == BOTTOM) ? (h - 1) : 0, 0 };
2018
2019 // Dst contains borders, so it is expressed in the [-1, width], [-1, height] space
2020 bool dstHorizontal = ((dstEdge == TOP) || (dstEdge == BOTTOM));
2021 int dstDelta = (dstHorizontal ? bytes : pitchB) * (reverse ? -1 : 1);
2022 VkOffset3D dstOffset = { (dstEdge == RIGHT) ? w : -1, (dstEdge == BOTTOM) ? h : -1, 0 };
2023
2024 // Don't write in the corners
2025 if(dstHorizontal)
2026 {
2027 dstOffset.x += reverse ? w : 1;
2028 }
2029 else
2030 {
2031 dstOffset.y += reverse ? h : 1;
2032 }
2033
2034 const uint8_t* src = static_cast<const uint8_t*>(image->getTexelPointer(srcOffset, srcSubresourceLayers));
2035 uint8_t *dst = static_cast<uint8_t*>(image->getTexelPointer(dstOffset, dstSubresourceLayers));
2036 ASSERT((src < image->end()) && ((src + (w * srcDelta)) < image->end()));
2037 ASSERT((dst < image->end()) && ((dst + (w * dstDelta)) < image->end()));
2038
2039 for(int i = 0; i < w; ++i, dst += dstDelta, src += srcDelta)
2040 {
2041 memcpy(dst, src, bytes);
2042 }
2043 }
Nicolas Capens68a82382018-10-02 13:16:55 -04002044}