blob: 8d5017839ae0124973714eae4c1cd0a572b77724 [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 Capens02cbe8e2019-08-05 15:10:05 -040019#include "System/Half.hpp"
Nicolas Capens1d8c8db2018-11-05 16:30:42 -050020#include "System/Memory.hpp"
Chris Forbesebe5f7f2019-01-16 10:38:34 -080021#include "Vulkan/VkDebug.hpp"
Alexis Hetu33642272019-03-01 11:55:59 -050022#include "Vulkan/VkImage.hpp"
Chris Forbes529eda32019-05-08 10:27:05 -070023#include "Vulkan/VkBuffer.hpp"
Nicolas Capens68a82382018-10-02 13:16:55 -040024
Nicolas Capensb8c63932019-03-19 01:52:40 -040025#include <utility>
26
Nicolas Capens68a82382018-10-02 13:16:55 -040027namespace sw
28{
Alexis Hetuf60a2d52019-05-09 14:16:05 -040029 Blitter::Blitter() :
30 blitMutex(),
31 blitCache(1024),
32 cornerUpdateMutex(),
33 cornerUpdateCache(64) // We only need one of these per format
Nicolas Capens68a82382018-10-02 13:16:55 -040034 {
Nicolas Capens68a82382018-10-02 13:16:55 -040035 }
36
37 Blitter::~Blitter()
38 {
Nicolas Capens68a82382018-10-02 13:16:55 -040039 }
40
Alexis Hetu04dae5e2019-04-08 13:41:50 -040041 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 -050042 {
43 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask);
Nicolas Capenscfe11c72019-05-16 09:58:26 -040044 vk::Format dstFormat = viewFormat.getAspectFormat(aspect);
Alexis Hetu04dae5e2019-04-08 13:41:50 -040045 if(dstFormat == VK_FORMAT_UNDEFINED)
Alexis Hetu33642272019-03-01 11:55:59 -050046 {
47 return;
48 }
49
Alexis Hetu04dae5e2019-04-08 13:41:50 -040050 if(fastClear(pixel, format, dest, dstFormat, subresourceRange, renderArea))
Alexis Hetu33642272019-03-01 11:55:59 -050051 {
52 return;
53 }
54
Alexis Hetu04dae5e2019-04-08 13:41:50 -040055 State state(format, dstFormat, 1, dest->getSampleCountFlagBits(), { 0xF });
Ben Clayton6897e9b2019-07-16 17:27:27 +010056 auto blitRoutine = getBlitRoutine(state);
Alexis Hetu33642272019-03-01 11:55:59 -050057 if(!blitRoutine)
58 {
59 return;
60 }
61
62 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
63
64 VkImageSubresourceLayers subresLayers =
65 {
66 subresourceRange.aspectMask,
67 subresourceRange.baseMipLevel,
68 subresourceRange.baseArrayLayer,
69 1
70 };
71
72 uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange);
73 uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange);
74
75 VkRect2D area = { { 0, 0 }, { 0, 0 } };
76 if(renderArea)
77 {
78 ASSERT(subresourceRange.levelCount == 1);
79 area = *renderArea;
80 }
81
82 for(; subresLayers.mipLevel <= lastMipLevel; subresLayers.mipLevel++)
83 {
Nicolas Capensba873302019-05-16 11:25:27 -040084 VkExtent3D extent = dest->getMipLevelExtent(aspect, subresLayers.mipLevel);
Alexis Hetu33642272019-03-01 11:55:59 -050085 if(!renderArea)
86 {
87 area.extent.width = extent.width;
88 area.extent.height = extent.height;
89 }
90
91 BlitData data =
92 {
93 pixel, nullptr, // source, dest
94
Alexis Hetu25ec7b02019-03-12 14:19:22 -040095 format.bytes(), // sPitchB
Alexis Hetu33642272019-03-01 11:55:59 -050096 dest->rowPitchBytes(aspect, subresLayers.mipLevel), // dPitchB
Alexis Hetu54ec7592019-03-20 14:37:16 -040097 0, // sSliceB (unused in clear operations)
Alexis Hetu33642272019-03-01 11:55:59 -050098 dest->slicePitchBytes(aspect, subresLayers.mipLevel), // dSliceB
99
100 0.5f, 0.5f, 0.0f, 0.0f, // x0, y0, w, h
101
102 area.offset.y, static_cast<int>(area.offset.y + area.extent.height), // y0d, y1d
103 area.offset.x, static_cast<int>(area.offset.x + area.extent.width), // x0d, x1d
104
105 0, 0, // sWidth, sHeight
106 };
107
Chris Forbes15bf1ef2019-05-02 17:19:12 -0700108 if (renderArea && dest->is3DSlice())
Alexis Hetu33642272019-03-01 11:55:59 -0500109 {
Chris Forbes15bf1ef2019-05-02 17:19:12 -0700110 // Reinterpret layers as depth slices
111 subresLayers.baseArrayLayer = 0;
112 subresLayers.layerCount = 1;
113 for (uint32_t depth = subresourceRange.baseArrayLayer; depth <= lastLayer; depth++)
Alexis Hetu33642272019-03-01 11:55:59 -0500114 {
Chris Forbes15bf1ef2019-05-02 17:19:12 -0700115 data.dest = dest->getTexelPointer({0, 0, static_cast<int32_t>(depth)}, subresLayers);
Alexis Hetu33642272019-03-01 11:55:59 -0500116 blitFunction(&data);
117 }
118 }
Chris Forbes15bf1ef2019-05-02 17:19:12 -0700119 else
120 {
121 for(subresLayers.baseArrayLayer = subresourceRange.baseArrayLayer; subresLayers.baseArrayLayer <= lastLayer; subresLayers.baseArrayLayer++)
122 {
123 for(uint32_t depth = 0; depth < extent.depth; depth++)
124 {
125 data.dest = dest->getTexelPointer({ 0, 0, static_cast<int32_t>(depth) }, subresLayers);
126
127 blitFunction(&data);
128 }
129 }
130 }
Alexis Hetu33642272019-03-01 11:55:59 -0500131 }
132 }
133
Alexis Hetu04dae5e2019-04-08 13:41:50 -0400134 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 -0500135 {
136 if(format != VK_FORMAT_R32G32B32A32_SFLOAT)
137 {
138 return false;
139 }
140
141 float *color = (float*)pixel;
142 float r = color[0];
143 float g = color[1];
144 float b = color[2];
145 float a = color[3];
146
147 uint32_t packed;
148
149 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask);
Alexis Hetu04dae5e2019-04-08 13:41:50 -0400150 switch(viewFormat)
Alexis Hetu33642272019-03-01 11:55:59 -0500151 {
152 case VK_FORMAT_R5G6B5_UNORM_PACK16:
153 packed = ((uint16_t)(31 * b + 0.5f) << 0) |
154 ((uint16_t)(63 * g + 0.5f) << 5) |
155 ((uint16_t)(31 * r + 0.5f) << 11);
156 break;
157 case VK_FORMAT_B5G6R5_UNORM_PACK16:
158 packed = ((uint16_t)(31 * r + 0.5f) << 0) |
159 ((uint16_t)(63 * g + 0.5f) << 5) |
160 ((uint16_t)(31 * b + 0.5f) << 11);
161 break;
162 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
163 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
164 case VK_FORMAT_R8G8B8A8_UNORM:
165 packed = ((uint32_t)(255 * a + 0.5f) << 24) |
166 ((uint32_t)(255 * b + 0.5f) << 16) |
167 ((uint32_t)(255 * g + 0.5f) << 8) |
168 ((uint32_t)(255 * r + 0.5f) << 0);
169 break;
170 case VK_FORMAT_B8G8R8A8_UNORM:
171 packed = ((uint32_t)(255 * a + 0.5f) << 24) |
172 ((uint32_t)(255 * r + 0.5f) << 16) |
173 ((uint32_t)(255 * g + 0.5f) << 8) |
174 ((uint32_t)(255 * b + 0.5f) << 0);
175 break;
176 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
177 packed = R11G11B10F(color);
178 break;
179 case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
180 packed = RGB9E5(color);
181 break;
182 default:
183 return false;
184 }
185
Ben Clayton00424c12019-03-17 17:29:30 +0000186 VkImageSubresourceLayers subresLayers =
Alexis Hetu33642272019-03-01 11:55:59 -0500187 {
188 subresourceRange.aspectMask,
189 subresourceRange.baseMipLevel,
190 subresourceRange.baseArrayLayer,
191 1
192 };
193 uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange);
194 uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange);
195
196 VkRect2D area = { { 0, 0 }, { 0, 0 } };
197 if(renderArea)
198 {
199 ASSERT(subresourceRange.levelCount == 1);
200 area = *renderArea;
201 }
202
203 for(; subresLayers.mipLevel <= lastMipLevel; subresLayers.mipLevel++)
204 {
205 int rowPitchBytes = dest->rowPitchBytes(aspect, subresLayers.mipLevel);
206 int slicePitchBytes = dest->slicePitchBytes(aspect, subresLayers.mipLevel);
Nicolas Capensba873302019-05-16 11:25:27 -0400207 VkExtent3D extent = dest->getMipLevelExtent(aspect, subresLayers.mipLevel);
Alexis Hetu33642272019-03-01 11:55:59 -0500208 if(!renderArea)
209 {
210 area.extent.width = extent.width;
211 area.extent.height = extent.height;
212 }
Alexis Hetu32ac8312019-04-15 17:20:29 -0400213 if(dest->is3DSlice())
214 {
215 extent.depth = 1; // The 3D image is instead interpreted as a 2D image with layers
216 }
Alexis Hetu33642272019-03-01 11:55:59 -0500217
218 for(subresLayers.baseArrayLayer = subresourceRange.baseArrayLayer; subresLayers.baseArrayLayer <= lastLayer; subresLayers.baseArrayLayer++)
219 {
220 for(uint32_t depth = 0; depth < extent.depth; depth++)
221 {
222 uint8_t *slice = (uint8_t*)dest->getTexelPointer(
223 { area.offset.x, area.offset.y, static_cast<int32_t>(depth) }, subresLayers);
224
225 for(int j = 0; j < dest->getSampleCountFlagBits(); j++)
226 {
227 uint8_t *d = slice;
228
Alexis Hetu04dae5e2019-04-08 13:41:50 -0400229 switch(viewFormat.bytes())
Alexis Hetu33642272019-03-01 11:55:59 -0500230 {
231 case 2:
232 for(uint32_t i = 0; i < area.extent.height; i++)
233 {
Alexis Hetu32ac8312019-04-15 17:20:29 -0400234 ASSERT(d < dest->end());
Alexis Hetu126bd7a2019-05-10 17:07:42 -0400235 sw::clear((uint16_t*)d, static_cast<uint16_t>(packed), area.extent.width);
Alexis Hetu33642272019-03-01 11:55:59 -0500236 d += rowPitchBytes;
237 }
238 break;
239 case 4:
240 for(uint32_t i = 0; i < area.extent.height; i++)
241 {
Alexis Hetu32ac8312019-04-15 17:20:29 -0400242 ASSERT(d < dest->end());
Alexis Hetu33642272019-03-01 11:55:59 -0500243 sw::clear((uint32_t*)d, packed, area.extent.width);
244 d += rowPitchBytes;
245 }
246 break;
247 default:
248 assert(false);
249 }
250
251 slice += slicePitchBytes;
252 }
253 }
254 }
255 }
256
257 return true;
258 }
259
Nicolas Capens68a82382018-10-02 13:16:55 -0400260 bool Blitter::read(Float4 &c, Pointer<Byte> element, const State &state)
261 {
262 c = Float4(0.0f, 0.0f, 0.0f, 1.0f);
263
264 switch(state.sourceFormat)
265 {
Alexis Hetua28671d2018-12-19 17:23:26 -0500266 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
267 c.w = Float(Int(*Pointer<Byte>(element)) & Int(0xF));
268 c.x = Float((Int(*Pointer<Byte>(element)) >> 4) & Int(0xF));
269 c.y = Float(Int(*Pointer<Byte>(element + 1)) & Int(0xF));
270 c.z = Float((Int(*Pointer<Byte>(element + 1)) >> 4) & Int(0xF));
271 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500272 case VK_FORMAT_R8_SINT:
273 case VK_FORMAT_R8_SNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400274 c.x = Float(Int(*Pointer<SByte>(element)));
275 c.w = float(0x7F);
276 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500277 case VK_FORMAT_R8_UNORM:
278 case VK_FORMAT_R8_UINT:
Hernan Liatis762741b2019-06-26 17:57:55 -0700279 case VK_FORMAT_R8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400280 c.x = Float(Int(*Pointer<Byte>(element)));
281 c.w = float(0xFF);
282 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500283 case VK_FORMAT_R16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400284 c.x = Float(Int(*Pointer<Short>(element)));
285 c.w = float(0x7FFF);
286 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500287 case VK_FORMAT_R16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400288 c.x = Float(Int(*Pointer<UShort>(element)));
289 c.w = float(0xFFFF);
290 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500291 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400292 c.x = Float(*Pointer<Int>(element));
293 c.w = float(0x7FFFFFFF);
294 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500295 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400296 c.x = Float(*Pointer<UInt>(element));
297 c.w = float(0xFFFFFFFF);
298 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500299 case VK_FORMAT_B8G8R8A8_SRGB:
Alexis Hetudd152e12018-11-14 13:39:28 -0500300 case VK_FORMAT_B8G8R8A8_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400301 c = Float4(*Pointer<Byte4>(element)).zyxw;
302 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500303 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500304 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500305 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500306 case VK_FORMAT_R8G8B8A8_SNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400307 c = Float4(*Pointer<SByte4>(element));
308 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500309 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
310 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500311 case VK_FORMAT_R8G8B8A8_UNORM:
312 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500313 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500314 case VK_FORMAT_R8G8B8A8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400315 c = Float4(*Pointer<Byte4>(element));
316 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500317 case VK_FORMAT_R16G16B16A16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400318 c = Float4(*Pointer<Short4>(element));
319 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500320 case VK_FORMAT_R16G16B16A16_UNORM:
321 case VK_FORMAT_R16G16B16A16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400322 c = Float4(*Pointer<UShort4>(element));
323 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500324 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400325 c = Float4(*Pointer<Int4>(element));
326 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500327 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400328 c = Float4(*Pointer<UInt4>(element));
329 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500330 case VK_FORMAT_R8G8_SINT:
331 case VK_FORMAT_R8G8_SNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400332 c.x = Float(Int(*Pointer<SByte>(element + 0)));
333 c.y = Float(Int(*Pointer<SByte>(element + 1)));
334 c.w = float(0x7F);
335 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500336 case VK_FORMAT_R8G8_UNORM:
337 case VK_FORMAT_R8G8_UINT:
Alexis Hetu45d34d22019-06-28 15:58:54 -0400338 case VK_FORMAT_R8G8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400339 c.x = Float(Int(*Pointer<Byte>(element + 0)));
340 c.y = Float(Int(*Pointer<Byte>(element + 1)));
341 c.w = float(0xFF);
342 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500343 case VK_FORMAT_R16G16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400344 c.x = Float(Int(*Pointer<Short>(element + 0)));
345 c.y = Float(Int(*Pointer<Short>(element + 2)));
346 c.w = float(0x7FFF);
347 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500348 case VK_FORMAT_R16G16_UNORM:
349 case VK_FORMAT_R16G16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400350 c.x = Float(Int(*Pointer<UShort>(element + 0)));
351 c.y = Float(Int(*Pointer<UShort>(element + 2)));
352 c.w = float(0xFFFF);
353 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500354 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400355 c.x = Float(*Pointer<Int>(element + 0));
356 c.y = Float(*Pointer<Int>(element + 4));
357 c.w = float(0x7FFFFFFF);
358 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500359 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400360 c.x = Float(*Pointer<UInt>(element + 0));
361 c.y = Float(*Pointer<UInt>(element + 4));
362 c.w = float(0xFFFFFFFF);
363 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500364 case VK_FORMAT_R32G32B32A32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400365 c = *Pointer<Float4>(element);
366 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500367 case VK_FORMAT_R32G32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400368 c.x = *Pointer<Float>(element + 0);
369 c.y = *Pointer<Float>(element + 4);
370 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500371 case VK_FORMAT_R32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400372 c.x = *Pointer<Float>(element);
373 break;
Ben Clayton00424c12019-03-17 17:29:30 +0000374 case VK_FORMAT_R16G16B16A16_SFLOAT:
375 c.w = Float(*Pointer<Half>(element + 6));
376 case VK_FORMAT_R16G16B16_SFLOAT:
377 c.z = Float(*Pointer<Half>(element + 4));
378 case VK_FORMAT_R16G16_SFLOAT:
379 c.y = Float(*Pointer<Half>(element + 2));
380 case VK_FORMAT_R16_SFLOAT:
381 c.x = Float(*Pointer<Half>(element));
Alexis Hetu734e2572018-12-20 14:00:49 -0500382 break;
Alexis Hetu5131ec92018-12-20 16:14:21 -0500383 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
384 // 10 (or 11) bit float formats are unsigned formats with a 5 bit exponent and a 5 (or 6) bit mantissa.
385 // Since the Half float format also has a 5 bit exponent, we can convert these formats to half by
386 // copy/pasting the bits so the the exponent bits and top mantissa bits are aligned to the half format.
387 // In this case, we have:
388 // 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
389 // 1st Short: |xxxxxxxxxx---------------------|
390 // 2nd Short: |xxxx---------------------xxxxxx|
391 // 3rd Short: |--------------------xxxxxxxxxxxx|
392 // These memory reads overlap, but each of them contains an entire channel, so we can read this without
393 // any int -> short conversion.
394 c.x = Float(As<Half>((*Pointer<UShort>(element + 0) & UShort(0x07FF)) << UShort(4)));
395 c.y = Float(As<Half>((*Pointer<UShort>(element + 1) & UShort(0x3FF8)) << UShort(1)));
396 c.z = Float(As<Half>((*Pointer<UShort>(element + 2) & UShort(0xFFC0)) >> UShort(1)));
397 break;
398 case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
399 // 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 +0000400 c.x = Float(*Pointer<UInt>(element) & UInt(0x000001FF)); // R's mantissa (bits 0-8)
401 c.y = Float((*Pointer<UInt>(element) & UInt(0x0003FE00)) >> 9); // G's mantissa (bits 9-17)
Alexis Hetu5131ec92018-12-20 16:14:21 -0500402 c.z = Float((*Pointer<UInt>(element) & UInt(0x07FC0000)) >> 18); // B's mantissa (bits 18-26)
403 c *= Float4(
404 // 2^E, using the exponent (bits 27-31) and treating it as an unsigned integer value
405 Float(UInt(1) << ((*Pointer<UInt>(element) & UInt(0xF8000000)) >> 27)) *
406 // Since the 9 bit mantissa values currently stored in RGB were converted straight
407 // from int to float (in the [0, 1<<9] range instead of the [0, 1] range), they
408 // are (1 << 9) times too high.
409 // Also, the exponent has 5 bits and we compute the exponent bias of floating point
410 // formats using "2^(k-1) - 1", so, in this case, the exponent bias is 2^(5-1)-1 = 15
411 // Exponent bias (15) + number of mantissa bits per component (9) = 24
412 Float(1.0f / (1 << 24)));
413 c.w = 1.0f;
414 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500415 case VK_FORMAT_R5G6B5_UNORM_PACK16:
Nicolas Capens68a82382018-10-02 13:16:55 -0400416 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
417 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07E0)) >> UShort(5)));
418 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
419 break;
Alexis Hetu457bd9b2018-12-20 13:18:18 -0500420 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
421 c.w = Float(Int((*Pointer<UShort>(element) & UShort(0x8000)) >> UShort(15)));
422 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0x7C00)) >> UShort(10)));
423 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x03E0)) >> UShort(5)));
424 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
425 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500426 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
427 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400428 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
429 c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
430 c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
431 c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
432 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500433 case VK_FORMAT_D16_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400434 c.x = Float(Int((*Pointer<UShort>(element))));
435 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500436 case VK_FORMAT_D24_UNORM_S8_UINT:
437 case VK_FORMAT_X8_D24_UNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400438 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0xFFFFFF00)) >> 8));
439 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500440 case VK_FORMAT_D32_SFLOAT:
441 case VK_FORMAT_D32_SFLOAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400442 c.x = *Pointer<Float>(element);
443 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500444 case VK_FORMAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400445 c.x = Float(Int(*Pointer<Byte>(element)));
446 break;
447 default:
448 return false;
449 }
450
451 return true;
452 }
453
454 bool Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
455 {
456 bool writeR = state.writeRed;
457 bool writeG = state.writeGreen;
458 bool writeB = state.writeBlue;
459 bool writeA = state.writeAlpha;
460 bool writeRGBA = writeR && writeG && writeB && writeA;
461
462 switch(state.destFormat)
463 {
Alexis Hetue04d9b02019-01-16 14:42:24 -0500464 case VK_FORMAT_R4G4_UNORM_PACK8:
465 if(writeR | writeG)
466 {
467 if(!writeR)
468 {
469 *Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
470 (*Pointer<Byte>(element) & Byte(0xF0));
471 }
472 else if(!writeG)
473 {
474 *Pointer<Byte>(element) = (*Pointer<Byte>(element) & Byte(0xF)) |
475 (Byte(RoundInt(Float(c.x))) << Byte(4));
476 }
477 else
478 {
479 *Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
480 (Byte(RoundInt(Float(c.x))) << Byte(4));
481 }
482 }
483 break;
484 case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
485 if(writeR || writeG || writeB || writeA)
486 {
487 *Pointer<UShort>(element) = (writeR ? ((UShort(RoundInt(Float(c.x))) & UShort(0xF)) << UShort(12)) :
488 (*Pointer<UShort>(element) & UShort(0x000F))) |
489 (writeG ? ((UShort(RoundInt(Float(c.y))) & UShort(0xF)) << UShort(8)) :
490 (*Pointer<UShort>(element) & UShort(0x00F0))) |
491 (writeB ? ((UShort(RoundInt(Float(c.z))) & UShort(0xF)) << UShort(4)) :
492 (*Pointer<UShort>(element) & UShort(0x0F00))) |
493 (writeA ? (UShort(RoundInt(Float(c.w))) & UShort(0xF)) :
494 (*Pointer<UShort>(element) & UShort(0xF000)));
495 }
496 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500497 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
498 if(writeRGBA)
499 {
Ben Clayton00424c12019-03-17 17:29:30 +0000500 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) & Int(0xF)) |
501 UShort((RoundInt(Float(c.x)) & Int(0xF)) << 4) |
502 UShort((RoundInt(Float(c.y)) & Int(0xF)) << 8) |
503 UShort((RoundInt(Float(c.z)) & Int(0xF)) << 12);
Alexis Hetua28671d2018-12-19 17:23:26 -0500504 }
505 else
506 {
507 unsigned short mask = (writeA ? 0x000F : 0x0000) |
508 (writeR ? 0x00F0 : 0x0000) |
509 (writeG ? 0x0F00 : 0x0000) |
510 (writeB ? 0xF000 : 0x0000);
511 unsigned short unmask = ~mask;
512 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
Ben Clayton00424c12019-03-17 17:29:30 +0000513 ((UShort(RoundInt(Float(c.w)) & Int(0xF)) |
514 UShort((RoundInt(Float(c.x)) & Int(0xF)) << 4) |
515 UShort((RoundInt(Float(c.y)) & Int(0xF)) << 8) |
Alexis Hetua28671d2018-12-19 17:23:26 -0500516 UShort((RoundInt(Float(c.z)) & Int(0xF)) << 12)) & UShort(mask));
517 }
518 break;
519 case VK_FORMAT_B8G8R8A8_SRGB:
Alexis Hetudd152e12018-11-14 13:39:28 -0500520 case VK_FORMAT_B8G8R8A8_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400521 if(writeRGBA)
522 {
523 Short4 c0 = RoundShort4(c.zyxw);
524 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
525 }
526 else
527 {
528 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
529 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
530 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
531 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
532 }
533 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500534 case VK_FORMAT_B8G8R8_SNORM:
535 if(writeB) { *Pointer<SByte>(element + 0) = SByte(RoundInt(Float(c.z))); }
536 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
537 if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
538 break;
539 case VK_FORMAT_B8G8R8_UNORM:
540 case VK_FORMAT_B8G8R8_SRGB:
541 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
542 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
543 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
544 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500545 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500546 case VK_FORMAT_R8G8B8A8_UNORM:
Alexis Hetua28671d2018-12-19 17:23:26 -0500547 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500548 case VK_FORMAT_R8G8B8A8_SRGB:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500549 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
550 case VK_FORMAT_R8G8B8A8_UINT:
551 case VK_FORMAT_R8G8B8A8_USCALED:
552 case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400553 if(writeRGBA)
554 {
555 Short4 c0 = RoundShort4(c);
556 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
557 }
558 else
559 {
560 if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
561 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
562 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
563 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
564 }
565 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500566 case VK_FORMAT_R32G32B32A32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400567 if(writeRGBA)
568 {
569 *Pointer<Float4>(element) = c;
570 }
571 else
572 {
573 if(writeR) { *Pointer<Float>(element) = c.x; }
574 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
575 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
576 if(writeA) { *Pointer<Float>(element + 12) = c.w; }
577 }
578 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500579 case VK_FORMAT_R32G32B32_SFLOAT:
580 if(writeR) { *Pointer<Float>(element) = c.x; }
581 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
582 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
583 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500584 case VK_FORMAT_R32G32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400585 if(writeR && writeG)
586 {
587 *Pointer<Float2>(element) = Float2(c);
588 }
589 else
590 {
591 if(writeR) { *Pointer<Float>(element) = c.x; }
592 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
593 }
594 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500595 case VK_FORMAT_R32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400596 if(writeR) { *Pointer<Float>(element) = c.x; }
597 break;
Ben Clayton00424c12019-03-17 17:29:30 +0000598 case VK_FORMAT_R16G16B16A16_SFLOAT:
599 if(writeA) { *Pointer<Half>(element + 6) = Half(c.w); }
600 case VK_FORMAT_R16G16B16_SFLOAT:
601 if(writeB) { *Pointer<Half>(element + 4) = Half(c.z); }
602 case VK_FORMAT_R16G16_SFLOAT:
603 if(writeG) { *Pointer<Half>(element + 2) = Half(c.y); }
604 case VK_FORMAT_R16_SFLOAT:
605 if(writeR) { *Pointer<Half>(element) = Half(c.x); }
Alexis Hetu734e2572018-12-20 14:00:49 -0500606 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500607 case VK_FORMAT_B8G8R8A8_SNORM:
608 if(writeB) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.z))); }
609 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
610 if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
611 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
612 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500613 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500614 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500615 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500616 case VK_FORMAT_R8G8B8A8_SNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500617 case VK_FORMAT_R8G8B8A8_SSCALED:
618 case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400619 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
Alexis Hetue04d9b02019-01-16 14:42:24 -0500620 case VK_FORMAT_R8G8B8_SINT:
621 case VK_FORMAT_R8G8B8_SNORM:
622 case VK_FORMAT_R8G8B8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400623 if(writeB) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.z))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500624 case VK_FORMAT_R8G8_SINT:
625 case VK_FORMAT_R8G8_SNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500626 case VK_FORMAT_R8G8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400627 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500628 case VK_FORMAT_R8_SINT:
629 case VK_FORMAT_R8_SNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500630 case VK_FORMAT_R8_SSCALED:
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:
Alexis Hetu45d34d22019-06-28 15:58:54 -0400636 case VK_FORMAT_R8G8B8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400637 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500638 case VK_FORMAT_R8G8_UINT:
639 case VK_FORMAT_R8G8_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500640 case VK_FORMAT_R8G8_USCALED:
Alexis Hetu45d34d22019-06-28 15:58:54 -0400641 case VK_FORMAT_R8G8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400642 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500643 case VK_FORMAT_R8_UINT:
644 case VK_FORMAT_R8_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500645 case VK_FORMAT_R8_USCALED:
Hernan Liatis762741b2019-06-26 17:57:55 -0700646 case VK_FORMAT_R8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400647 if(writeR) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x))); }
648 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500649 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500650 case VK_FORMAT_R16G16B16A16_SNORM:
651 case VK_FORMAT_R16G16B16A16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400652 if(writeRGBA)
653 {
654 *Pointer<Short4>(element) = Short4(RoundInt(c));
655 }
656 else
657 {
658 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
659 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
660 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
661 if(writeA) { *Pointer<Short>(element + 6) = Short(RoundInt(Float(c.w))); }
662 }
663 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500664 case VK_FORMAT_R16G16B16_SINT:
665 case VK_FORMAT_R16G16B16_SNORM:
666 case VK_FORMAT_R16G16B16_SSCALED:
667 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
668 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
669 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
670 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500671 case VK_FORMAT_R16G16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500672 case VK_FORMAT_R16G16_SNORM:
673 case VK_FORMAT_R16G16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400674 if(writeR && writeG)
675 {
676 *Pointer<Short2>(element) = Short2(Short4(RoundInt(c)));
677 }
678 else
679 {
680 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
681 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
682 }
683 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500684 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500685 case VK_FORMAT_R16_SNORM:
686 case VK_FORMAT_R16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400687 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
688 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500689 case VK_FORMAT_R16G16B16A16_UINT:
690 case VK_FORMAT_R16G16B16A16_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500691 case VK_FORMAT_R16G16B16A16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400692 if(writeRGBA)
693 {
694 *Pointer<UShort4>(element) = UShort4(RoundInt(c));
695 }
696 else
697 {
698 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
699 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
700 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
701 if(writeA) { *Pointer<UShort>(element + 6) = UShort(RoundInt(Float(c.w))); }
702 }
703 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500704 case VK_FORMAT_R16G16B16_UINT:
705 case VK_FORMAT_R16G16B16_UNORM:
706 case VK_FORMAT_R16G16B16_USCALED:
707 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
708 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
709 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
710 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500711 case VK_FORMAT_R16G16_UINT:
712 case VK_FORMAT_R16G16_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500713 case VK_FORMAT_R16G16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400714 if(writeR && writeG)
715 {
716 *Pointer<UShort2>(element) = UShort2(UShort4(RoundInt(c)));
717 }
718 else
719 {
720 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
721 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
722 }
723 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500724 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500725 case VK_FORMAT_R16_UNORM:
726 case VK_FORMAT_R16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400727 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
728 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500729 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400730 if(writeRGBA)
731 {
732 *Pointer<Int4>(element) = RoundInt(c);
733 }
734 else
735 {
736 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
737 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
738 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
739 if(writeA) { *Pointer<Int>(element + 12) = RoundInt(Float(c.w)); }
740 }
741 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500742 case VK_FORMAT_R32G32B32_SINT:
743 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500744 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400745 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500746 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400747 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
748 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500749 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400750 if(writeRGBA)
751 {
752 *Pointer<UInt4>(element) = UInt4(RoundInt(c));
753 }
754 else
755 {
756 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
757 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
758 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
759 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(RoundInt(Float(c.w))); }
760 }
761 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500762 case VK_FORMAT_R32G32B32_UINT:
763 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500764 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400765 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500766 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400767 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
768 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500769 case VK_FORMAT_R5G6B5_UNORM_PACK16:
Nicolas Capens68a82382018-10-02 13:16:55 -0400770 if(writeR && writeG && writeB)
771 {
772 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.z)) |
773 (RoundInt(Float(c.y)) << Int(5)) |
774 (RoundInt(Float(c.x)) << Int(11)));
775 }
776 else
777 {
778 unsigned short mask = (writeB ? 0x001F : 0x0000) | (writeG ? 0x07E0 : 0x0000) | (writeR ? 0xF800 : 0x0000);
779 unsigned short unmask = ~mask;
780 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
781 (UShort(RoundInt(Float(c.z)) |
782 (RoundInt(Float(c.y)) << Int(5)) |
783 (RoundInt(Float(c.x)) << Int(11))) & UShort(mask));
784 }
785 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500786 case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
787 if(writeRGBA)
788 {
789 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) |
790 (RoundInt(Float(c.z)) << Int(1)) |
791 (RoundInt(Float(c.y)) << Int(6)) |
792 (RoundInt(Float(c.x)) << Int(11)));
793 }
794 else
795 {
796 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
797 (writeR ? 0x7C00 : 0x0000) |
798 (writeG ? 0x03E0 : 0x0000) |
799 (writeB ? 0x001F : 0x0000);
800 unsigned short unmask = ~mask;
801 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
802 (UShort(RoundInt(Float(c.w)) |
803 (RoundInt(Float(c.z)) << Int(1)) |
804 (RoundInt(Float(c.y)) << Int(6)) |
805 (RoundInt(Float(c.x)) << Int(11))) & UShort(mask));
806 }
807 break;
808 case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
809 if(writeRGBA)
810 {
811 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) |
812 (RoundInt(Float(c.x)) << Int(1)) |
813 (RoundInt(Float(c.y)) << Int(6)) |
814 (RoundInt(Float(c.z)) << Int(11)));
815 }
816 else
817 {
818 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
819 (writeR ? 0x7C00 : 0x0000) |
820 (writeG ? 0x03E0 : 0x0000) |
821 (writeB ? 0x001F : 0x0000);
822 unsigned short unmask = ~mask;
823 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
824 (UShort(RoundInt(Float(c.w)) |
825 (RoundInt(Float(c.x)) << Int(1)) |
826 (RoundInt(Float(c.y)) << Int(6)) |
827 (RoundInt(Float(c.z)) << Int(11))) & UShort(mask));
828 }
829 break;
Alexis Hetu457bd9b2018-12-20 13:18:18 -0500830 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
831 if(writeRGBA)
832 {
833 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.z)) |
834 (RoundInt(Float(c.y)) << Int(5)) |
835 (RoundInt(Float(c.x)) << Int(10)) |
836 (RoundInt(Float(c.w)) << Int(15)));
837 }
838 else
839 {
840 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
841 (writeR ? 0x7C00 : 0x0000) |
842 (writeG ? 0x03E0 : 0x0000) |
843 (writeB ? 0x001F : 0x0000);
844 unsigned short unmask = ~mask;
845 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
846 (UShort(RoundInt(Float(c.z)) |
847 (RoundInt(Float(c.y)) << Int(5)) |
848 (RoundInt(Float(c.x)) << Int(10)) |
849 (RoundInt(Float(c.w)) << Int(15))) & UShort(mask));
850 }
851 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500852 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
853 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500854 case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400855 if(writeRGBA)
856 {
857 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) |
858 (RoundInt(Float(c.y)) << 10) |
859 (RoundInt(Float(c.z)) << 20) |
860 (RoundInt(Float(c.w)) << 30));
861 }
862 else
863 {
864 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
865 (writeB ? 0x3FF00000 : 0x0000) |
866 (writeG ? 0x000FFC00 : 0x0000) |
867 (writeR ? 0x000003FF : 0x0000);
868 unsigned int unmask = ~mask;
869 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
870 (UInt(RoundInt(Float(c.x)) |
Alexis Hetua28671d2018-12-19 17:23:26 -0500871 (RoundInt(Float(c.y)) << 10) |
872 (RoundInt(Float(c.z)) << 20) |
873 (RoundInt(Float(c.w)) << 30)) & UInt(mask));
Nicolas Capens68a82382018-10-02 13:16:55 -0400874 }
875 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500876 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
877 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
878 case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
879 if(writeRGBA)
880 {
881 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.z)) |
882 (RoundInt(Float(c.y)) << 10) |
883 (RoundInt(Float(c.x)) << 20) |
884 (RoundInt(Float(c.w)) << 30));
885 }
886 else
887 {
888 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
889 (writeR ? 0x3FF00000 : 0x0000) |
890 (writeG ? 0x000FFC00 : 0x0000) |
891 (writeB ? 0x000003FF : 0x0000);
892 unsigned int unmask = ~mask;
893 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
894 (UInt(RoundInt(Float(c.z)) |
895 (RoundInt(Float(c.y)) << 10) |
896 (RoundInt(Float(c.x)) << 20) |
897 (RoundInt(Float(c.w)) << 30)) & UInt(mask));
898 }
899 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500900 case VK_FORMAT_D16_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400901 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x)));
902 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500903 case VK_FORMAT_D24_UNORM_S8_UINT:
904 case VK_FORMAT_X8_D24_UNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400905 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) << 8);
906 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500907 case VK_FORMAT_D32_SFLOAT:
908 case VK_FORMAT_D32_SFLOAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400909 *Pointer<Float>(element) = c.x;
910 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500911 case VK_FORMAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400912 *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
913 break;
914 default:
915 return false;
916 }
917 return true;
918 }
919
920 bool Blitter::read(Int4 &c, Pointer<Byte> element, const State &state)
921 {
922 c = Int4(0, 0, 0, 1);
923
924 switch(state.sourceFormat)
925 {
Alexis Hetua28671d2018-12-19 17:23:26 -0500926 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500927 case VK_FORMAT_R8G8B8A8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400928 c = Insert(c, Int(*Pointer<SByte>(element + 3)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500929 c = Insert(c, Int(*Pointer<SByte>(element + 2)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500930 case VK_FORMAT_R8G8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400931 c = Insert(c, Int(*Pointer<SByte>(element + 1)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500932 case VK_FORMAT_R8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400933 c = Insert(c, Int(*Pointer<SByte>(element)), 0);
934 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500935 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
936 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000003FF))), 0);
937 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10), 1);
938 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20), 2);
939 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30), 3);
940 break;
941 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500942 case VK_FORMAT_R8G8B8A8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400943 c = Insert(c, Int(*Pointer<Byte>(element + 3)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500944 c = Insert(c, Int(*Pointer<Byte>(element + 2)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500945 case VK_FORMAT_R8G8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400946 c = Insert(c, Int(*Pointer<Byte>(element + 1)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500947 case VK_FORMAT_R8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400948 c = Insert(c, Int(*Pointer<Byte>(element)), 0);
949 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500950 case VK_FORMAT_R16G16B16A16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400951 c = Insert(c, Int(*Pointer<Short>(element + 6)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500952 c = Insert(c, Int(*Pointer<Short>(element + 4)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500953 case VK_FORMAT_R16G16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400954 c = Insert(c, Int(*Pointer<Short>(element + 2)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500955 case VK_FORMAT_R16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400956 c = Insert(c, Int(*Pointer<Short>(element)), 0);
957 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500958 case VK_FORMAT_R16G16B16A16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400959 c = Insert(c, Int(*Pointer<UShort>(element + 6)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500960 c = Insert(c, Int(*Pointer<UShort>(element + 4)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500961 case VK_FORMAT_R16G16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400962 c = Insert(c, Int(*Pointer<UShort>(element + 2)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500963 case VK_FORMAT_R16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400964 c = Insert(c, Int(*Pointer<UShort>(element)), 0);
965 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500966 case VK_FORMAT_R32G32B32A32_SINT:
967 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400968 c = *Pointer<Int4>(element);
969 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500970 case VK_FORMAT_R32G32_SINT:
971 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400972 c = Insert(c, *Pointer<Int>(element + 4), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500973 case VK_FORMAT_R32_SINT:
974 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400975 c = Insert(c, *Pointer<Int>(element), 0);
976 break;
977 default:
978 return false;
979 }
980
981 return true;
982 }
983
984 bool Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
985 {
986 bool writeR = state.writeRed;
987 bool writeG = state.writeGreen;
988 bool writeB = state.writeBlue;
989 bool writeA = state.writeAlpha;
990 bool writeRGBA = writeR && writeG && writeB && writeA;
991
992 switch(state.destFormat)
993 {
Alexis Hetu6d8d3c32018-12-21 12:03:31 -0500994 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
995 c = Min(As<UInt4>(c), UInt4(0x03FF, 0x03FF, 0x03FF, 0x0003));
996 break;
997 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
998 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500999 case VK_FORMAT_R8G8B8_UINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001000 case VK_FORMAT_R8G8_UINT:
1001 case VK_FORMAT_R8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001002 case VK_FORMAT_R8G8B8A8_USCALED:
1003 case VK_FORMAT_R8G8B8_USCALED:
1004 case VK_FORMAT_R8G8_USCALED:
1005 case VK_FORMAT_R8_USCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001006 c = Min(As<UInt4>(c), UInt4(0xFF));
1007 break;
1008 case VK_FORMAT_R16G16B16A16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001009 case VK_FORMAT_R16G16B16_UINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001010 case VK_FORMAT_R16G16_UINT:
1011 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001012 case VK_FORMAT_R16G16B16A16_USCALED:
1013 case VK_FORMAT_R16G16B16_USCALED:
1014 case VK_FORMAT_R16G16_USCALED:
1015 case VK_FORMAT_R16_USCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001016 c = Min(As<UInt4>(c), UInt4(0xFFFF));
1017 break;
1018 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1019 case VK_FORMAT_R8G8B8A8_SINT:
1020 case VK_FORMAT_R8G8_SINT:
1021 case VK_FORMAT_R8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001022 case VK_FORMAT_R8G8B8A8_SSCALED:
1023 case VK_FORMAT_R8G8B8_SSCALED:
1024 case VK_FORMAT_R8G8_SSCALED:
1025 case VK_FORMAT_R8_SSCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001026 c = Min(Max(c, Int4(-0x80)), Int4(0x7F));
1027 break;
1028 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001029 case VK_FORMAT_R16G16B16_SINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001030 case VK_FORMAT_R16G16_SINT:
1031 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001032 case VK_FORMAT_R16G16B16A16_SSCALED:
1033 case VK_FORMAT_R16G16B16_SSCALED:
1034 case VK_FORMAT_R16G16_SSCALED:
1035 case VK_FORMAT_R16_SSCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001036 c = Min(Max(c, Int4(-0x8000)), Int4(0x7FFF));
1037 break;
1038 default:
1039 break;
1040 }
1041
1042 switch(state.destFormat)
1043 {
Alexis Hetue04d9b02019-01-16 14:42:24 -05001044 case VK_FORMAT_B8G8R8A8_SINT:
1045 case VK_FORMAT_B8G8R8A8_SSCALED:
1046 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
1047 case VK_FORMAT_B8G8R8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001048 case VK_FORMAT_B8G8R8_SSCALED:
1049 if(writeB) { *Pointer<SByte>(element) = SByte(Extract(c, 2)); }
1050 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
1051 if(writeR) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 0)); }
1052 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001053 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -05001054 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001055 case VK_FORMAT_R8G8B8A8_SSCALED:
1056 case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -04001057 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001058 case VK_FORMAT_R8G8B8_SINT:
1059 case VK_FORMAT_R8G8B8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001060 if(writeB) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001061 case VK_FORMAT_R8G8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001062 case VK_FORMAT_R8G8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001063 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001064 case VK_FORMAT_R8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001065 case VK_FORMAT_R8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001066 if(writeR) { *Pointer<SByte>(element) = SByte(Extract(c, 0)); }
1067 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001068 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001069 case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1070 case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
1071 case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
Alexis Hetua28671d2018-12-19 17:23:26 -05001072 if(writeRGBA)
1073 {
1074 *Pointer<UInt>(element) =
1075 UInt((Extract(c, 0)) | (Extract(c, 1) << 10) | (Extract(c, 2) << 20) | (Extract(c, 3) << 30));
1076 }
1077 else
1078 {
1079 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1080 (writeB ? 0x3FF00000 : 0x0000) |
1081 (writeG ? 0x000FFC00 : 0x0000) |
1082 (writeR ? 0x000003FF : 0x0000);
1083 unsigned int unmask = ~mask;
1084 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1085 (UInt(Extract(c, 0) | (Extract(c, 1) << 10) | (Extract(c, 2) << 20) | (Extract(c, 3) << 30)) & UInt(mask));
1086 }
1087 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001088 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1089 case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1090 case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
1091 case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
1092 if(writeRGBA)
1093 {
1094 *Pointer<UInt>(element) =
1095 UInt((Extract(c, 2)) | (Extract(c, 1) << 10) | (Extract(c, 0) << 20) | (Extract(c, 3) << 30));
1096 }
1097 else
1098 {
1099 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1100 (writeR ? 0x3FF00000 : 0x0000) |
1101 (writeG ? 0x000FFC00 : 0x0000) |
1102 (writeB ? 0x000003FF : 0x0000);
1103 unsigned int unmask = ~mask;
1104 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1105 (UInt(Extract(c, 2) | (Extract(c, 1) << 10) | (Extract(c, 0) << 20) | (Extract(c, 3) << 30)) & UInt(mask));
1106 }
1107 break;
1108 case VK_FORMAT_B8G8R8A8_UINT:
1109 case VK_FORMAT_B8G8R8A8_USCALED:
1110 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
1111 case VK_FORMAT_B8G8R8_UINT:
1112 case VK_FORMAT_B8G8R8_USCALED:
Alexis Hetu45d34d22019-06-28 15:58:54 -04001113 case VK_FORMAT_B8G8R8_SRGB:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001114 if(writeB) { *Pointer<Byte>(element) = Byte(Extract(c, 2)); }
1115 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
1116 if(writeR) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 0)); }
1117 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001118 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -05001119 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001120 case VK_FORMAT_R8G8B8A8_USCALED:
1121 case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -04001122 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001123 case VK_FORMAT_R8G8B8_UINT:
1124 case VK_FORMAT_R8G8B8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001125 if(writeB) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001126 case VK_FORMAT_R8G8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001127 case VK_FORMAT_R8G8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001128 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001129 case VK_FORMAT_R8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001130 case VK_FORMAT_R8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001131 if(writeR) { *Pointer<Byte>(element) = Byte(Extract(c, 0)); }
1132 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001133 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001134 case VK_FORMAT_R16G16B16A16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001135 if(writeA) { *Pointer<Short>(element + 6) = Short(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001136 case VK_FORMAT_R16G16B16_SINT:
1137 case VK_FORMAT_R16G16B16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001138 if(writeB) { *Pointer<Short>(element + 4) = Short(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001139 case VK_FORMAT_R16G16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001140 case VK_FORMAT_R16G16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001141 if(writeG) { *Pointer<Short>(element + 2) = Short(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001142 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001143 case VK_FORMAT_R16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001144 if(writeR) { *Pointer<Short>(element) = Short(Extract(c, 0)); }
1145 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001146 case VK_FORMAT_R16G16B16A16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001147 case VK_FORMAT_R16G16B16A16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001148 if(writeA) { *Pointer<UShort>(element + 6) = UShort(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001149 case VK_FORMAT_R16G16B16_UINT:
1150 case VK_FORMAT_R16G16B16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001151 if(writeB) { *Pointer<UShort>(element + 4) = UShort(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001152 case VK_FORMAT_R16G16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001153 case VK_FORMAT_R16G16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001154 if(writeG) { *Pointer<UShort>(element + 2) = UShort(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001155 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001156 case VK_FORMAT_R16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001157 if(writeR) { *Pointer<UShort>(element) = UShort(Extract(c, 0)); }
1158 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001159 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001160 if(writeRGBA)
1161 {
1162 *Pointer<Int4>(element) = c;
1163 }
1164 else
1165 {
1166 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1167 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1168 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1169 if(writeA) { *Pointer<Int>(element + 12) = Extract(c, 3); }
1170 }
1171 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001172 case VK_FORMAT_R32G32B32_SINT:
1173 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1174 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1175 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1176 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001177 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001178 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1179 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1180 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001181 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001182 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1183 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001184 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001185 if(writeRGBA)
1186 {
1187 *Pointer<UInt4>(element) = As<UInt4>(c);
1188 }
1189 else
1190 {
1191 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1192 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
1193 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
1194 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(Extract(c, 3)); }
1195 }
1196 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001197 case VK_FORMAT_R32G32B32_UINT:
1198 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001199 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001200 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001201 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001202 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1203 break;
1204 default:
1205 return false;
1206 }
1207
1208 return true;
1209 }
1210
Nicolas Capens68a82382018-10-02 13:16:55 -04001211 bool Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
1212 {
1213 float4 scale, unscale;
1214 if(state.clearOperation &&
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001215 state.sourceFormat.isNonNormalizedInteger() &&
1216 !state.destFormat.isNonNormalizedInteger())
Nicolas Capens68a82382018-10-02 13:16:55 -04001217 {
1218 // If we're clearing a buffer from an int or uint color into a normalized color,
1219 // then the whole range of the int or uint color must be scaled between 0 and 1.
1220 switch(state.sourceFormat)
1221 {
Alexis Hetudd152e12018-11-14 13:39:28 -05001222 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001223 unscale = replicate(static_cast<float>(0x7FFFFFFF));
1224 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001225 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001226 unscale = replicate(static_cast<float>(0xFFFFFFFF));
1227 break;
1228 default:
1229 return false;
1230 }
1231 }
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001232 else if(!state.sourceFormat.getScale(unscale))
Nicolas Capens68a82382018-10-02 13:16:55 -04001233 {
1234 return false;
1235 }
1236
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001237 if(!state.destFormat.getScale(scale))
Nicolas Capens68a82382018-10-02 13:16:55 -04001238 {
1239 return false;
1240 }
1241
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001242 bool srcSRGB = state.sourceFormat.isSRGBformat();
1243 bool dstSRGB = state.destFormat.isSRGBformat();
Nicolas Capens68a82382018-10-02 13:16:55 -04001244
1245 if(state.convertSRGB && ((srcSRGB && !preScaled) || dstSRGB)) // One of the formats is sRGB encoded.
1246 {
1247 value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) : // Unapply scale
1248 Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w); // Apply unscale
1249 value = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : LinearToSRGB(value);
1250 value *= Float4(scale.x, scale.y, scale.z, scale.w); // Apply scale
1251 }
1252 else if(unscale != scale)
1253 {
1254 value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
1255 }
1256
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001257 if(state.sourceFormat.isFloatFormat() && !state.destFormat.isFloatFormat())
Nicolas Capens68a82382018-10-02 13:16:55 -04001258 {
1259 value = Min(value, Float4(scale.x, scale.y, scale.z, scale.w));
1260
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001261 value = Max(value, Float4(state.destFormat.isUnsignedComponent(0) ? 0.0f : -scale.x,
1262 state.destFormat.isUnsignedComponent(1) ? 0.0f : -scale.y,
1263 state.destFormat.isUnsignedComponent(2) ? 0.0f : -scale.z,
1264 state.destFormat.isUnsignedComponent(3) ? 0.0f : -scale.w));
Nicolas Capens68a82382018-10-02 13:16:55 -04001265 }
1266
1267 return true;
1268 }
1269
1270 Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout)
1271 {
1272 if(!quadLayout)
1273 {
1274 return y * pitchB + x * bytes;
1275 }
1276 else
1277 {
1278 // (x & ~1) * 2 + (x & 1) == (x - (x & 1)) * 2 + (x & 1) == x * 2 - (x & 1) * 2 + (x & 1) == x * 2 - (x & 1)
1279 return (y & Int(~1)) * pitchB +
1280 ((y & Int(1)) * 2 + x * 2 - (x & Int(1))) * bytes;
1281 }
1282 }
1283
1284 Float4 Blitter::LinearToSRGB(Float4 &c)
1285 {
1286 Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
1287 Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
1288
1289 Float4 s = c;
1290 s.xyz = Max(lc, ec);
1291
1292 return s;
1293 }
1294
1295 Float4 Blitter::sRGBtoLinear(Float4 &c)
1296 {
1297 Float4 lc = c * Float4(1.0f / 12.92f);
1298 Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
1299
1300 Int4 linear = CmpLT(c, Float4(0.04045f));
1301
1302 Float4 s = c;
Ben Clayton5e9441a2019-05-24 07:43:42 +01001303 s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec))); // TODO: IfThenElse()
Nicolas Capens68a82382018-10-02 13:16:55 -04001304
1305 return s;
1306 }
1307
Ben Clayton6897e9b2019-07-16 17:27:27 +01001308 std::shared_ptr<Routine> Blitter::generate(const State &state)
Nicolas Capens68a82382018-10-02 13:16:55 -04001309 {
1310 Function<Void(Pointer<Byte>)> function;
1311 {
1312 Pointer<Byte> blit(function.Arg<0>());
1313
1314 Pointer<Byte> source = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,source));
1315 Pointer<Byte> dest = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,dest));
1316 Int sPitchB = *Pointer<Int>(blit + OFFSET(BlitData,sPitchB));
1317 Int dPitchB = *Pointer<Int>(blit + OFFSET(BlitData,dPitchB));
1318
1319 Float x0 = *Pointer<Float>(blit + OFFSET(BlitData,x0));
1320 Float y0 = *Pointer<Float>(blit + OFFSET(BlitData,y0));
1321 Float w = *Pointer<Float>(blit + OFFSET(BlitData,w));
1322 Float h = *Pointer<Float>(blit + OFFSET(BlitData,h));
1323
1324 Int x0d = *Pointer<Int>(blit + OFFSET(BlitData,x0d));
1325 Int x1d = *Pointer<Int>(blit + OFFSET(BlitData,x1d));
1326 Int y0d = *Pointer<Int>(blit + OFFSET(BlitData,y0d));
1327 Int y1d = *Pointer<Int>(blit + OFFSET(BlitData,y1d));
1328
1329 Int sWidth = *Pointer<Int>(blit + OFFSET(BlitData,sWidth));
1330 Int sHeight = *Pointer<Int>(blit + OFFSET(BlitData,sHeight));
1331
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001332 bool intSrc = state.sourceFormat.isNonNormalizedInteger();
1333 bool intDst = state.destFormat.isNonNormalizedInteger();
Nicolas Capens68a82382018-10-02 13:16:55 -04001334 bool intBoth = intSrc && intDst;
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001335 bool srcQuadLayout = state.sourceFormat.hasQuadLayout();
1336 bool dstQuadLayout = state.destFormat.hasQuadLayout();
1337 int srcBytes = state.sourceFormat.bytes();
1338 int dstBytes = state.destFormat.bytes();
Nicolas Capens68a82382018-10-02 13:16:55 -04001339
1340 bool hasConstantColorI = false;
1341 Int4 constantColorI;
1342 bool hasConstantColorF = false;
1343 Float4 constantColorF;
1344 if(state.clearOperation)
1345 {
1346 if(intBoth) // Integer types
1347 {
1348 if(!read(constantColorI, source, state))
1349 {
1350 return nullptr;
1351 }
1352 hasConstantColorI = true;
1353 }
1354 else
1355 {
1356 if(!read(constantColorF, source, state))
1357 {
1358 return nullptr;
1359 }
1360 hasConstantColorF = true;
1361
1362 if(!ApplyScaleAndClamp(constantColorF, state))
1363 {
1364 return nullptr;
1365 }
1366 }
1367 }
1368
1369 For(Int j = y0d, j < y1d, j++)
1370 {
1371 Float y = state.clearOperation ? RValue<Float>(y0) : y0 + Float(j) * h;
1372 Pointer<Byte> destLine = dest + (dstQuadLayout ? j & Int(~1) : RValue<Int>(j)) * dPitchB;
1373
1374 For(Int i = x0d, i < x1d, i++)
1375 {
1376 Float x = state.clearOperation ? RValue<Float>(x0) : x0 + Float(i) * w;
1377 Pointer<Byte> d = destLine + (dstQuadLayout ? (((j & Int(1)) << 1) + (i * 2) - (i & Int(1))) : RValue<Int>(i)) * dstBytes;
1378
1379 if(hasConstantColorI)
1380 {
1381 if(!write(constantColorI, d, state))
1382 {
1383 return nullptr;
1384 }
1385 }
1386 else if(hasConstantColorF)
1387 {
1388 for(int s = 0; s < state.destSamples; s++)
1389 {
1390 if(!write(constantColorF, d, state))
1391 {
1392 return nullptr;
1393 }
1394
1395 d += *Pointer<Int>(blit + OFFSET(BlitData, dSliceB));
1396 }
1397 }
1398 else if(intBoth) // Integer types do not support filtering
1399 {
1400 Int4 color; // When both formats are true integer types, we don't go to float to avoid losing precision
1401 Int X = Int(x);
1402 Int Y = Int(y);
1403
1404 if(state.clampToEdge)
1405 {
1406 X = Clamp(X, 0, sWidth - 1);
1407 Y = Clamp(Y, 0, sHeight - 1);
1408 }
1409
1410 Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1411
1412 if(!read(color, s, state))
1413 {
1414 return nullptr;
1415 }
1416
1417 if(!write(color, d, state))
1418 {
1419 return nullptr;
1420 }
1421 }
1422 else
1423 {
1424 Float4 color;
1425
1426 bool preScaled = false;
1427 if(!state.filter || intSrc)
1428 {
1429 Int X = Int(x);
1430 Int Y = Int(y);
1431
1432 if(state.clampToEdge)
1433 {
1434 X = Clamp(X, 0, sWidth - 1);
1435 Y = Clamp(Y, 0, sHeight - 1);
1436 }
1437
1438 Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1439
1440 if(!read(color, s, state))
1441 {
1442 return nullptr;
1443 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001444
1445 if(state.srcSamples > 1) // Resolve multisampled source
1446 {
Alexis Hetua4308132019-06-13 09:55:26 -04001447 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1448 {
1449 if(!ApplyScaleAndClamp(color, state)) return nullptr;
1450 preScaled = true;
1451 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001452 Float4 accum = color;
Alexis Hetu126bd7a2019-05-10 17:07:42 -04001453 for(int sample = 1; sample < state.srcSamples; sample++)
Alexis Hetu54ec7592019-03-20 14:37:16 -04001454 {
1455 s += *Pointer<Int>(blit + OFFSET(BlitData, sSliceB));
1456 if(!read(color, s, state))
1457 {
1458 return nullptr;
1459 }
Alexis Hetu3f80dad2019-05-22 18:23:47 -04001460 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1461 {
1462 if(!ApplyScaleAndClamp(color, state)) return nullptr;
1463 preScaled = true;
1464 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001465 accum += color;
1466 }
1467 color = accum * Float4(1.0f / static_cast<float>(state.srcSamples));
1468 }
Nicolas Capens68a82382018-10-02 13:16:55 -04001469 }
1470 else // Bilinear filtering
1471 {
1472 Float X = x;
1473 Float Y = y;
1474
1475 if(state.clampToEdge)
1476 {
1477 X = Min(Max(x, 0.5f), Float(sWidth) - 0.5f);
1478 Y = Min(Max(y, 0.5f), Float(sHeight) - 0.5f);
1479 }
1480
1481 Float x0 = X - 0.5f;
1482 Float y0 = Y - 0.5f;
1483
1484 Int X0 = Max(Int(x0), 0);
1485 Int Y0 = Max(Int(y0), 0);
1486
1487 Int X1 = X0 + 1;
1488 Int Y1 = Y0 + 1;
1489 X1 = IfThenElse(X1 >= sWidth, X0, X1);
1490 Y1 = IfThenElse(Y1 >= sHeight, Y0, Y1);
1491
1492 Pointer<Byte> s00 = source + ComputeOffset(X0, Y0, sPitchB, srcBytes, srcQuadLayout);
1493 Pointer<Byte> s01 = source + ComputeOffset(X1, Y0, sPitchB, srcBytes, srcQuadLayout);
1494 Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, sPitchB, srcBytes, srcQuadLayout);
1495 Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, sPitchB, srcBytes, srcQuadLayout);
1496
1497 Float4 c00; if(!read(c00, s00, state)) return nullptr;
1498 Float4 c01; if(!read(c01, s01, state)) return nullptr;
1499 Float4 c10; if(!read(c10, s10, state)) return nullptr;
1500 Float4 c11; if(!read(c11, s11, state)) return nullptr;
1501
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001502 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
Nicolas Capens68a82382018-10-02 13:16:55 -04001503 {
1504 if(!ApplyScaleAndClamp(c00, state)) return nullptr;
1505 if(!ApplyScaleAndClamp(c01, state)) return nullptr;
1506 if(!ApplyScaleAndClamp(c10, state)) return nullptr;
1507 if(!ApplyScaleAndClamp(c11, state)) return nullptr;
1508 preScaled = true;
1509 }
1510
1511 Float4 fx = Float4(x0 - Float(X0));
1512 Float4 fy = Float4(y0 - Float(Y0));
1513 Float4 ix = Float4(1.0f) - fx;
1514 Float4 iy = Float4(1.0f) - fy;
1515
1516 color = (c00 * ix + c01 * fx) * iy +
1517 (c10 * ix + c11 * fx) * fy;
1518 }
1519
1520 if(!ApplyScaleAndClamp(color, state, preScaled))
1521 {
1522 return nullptr;
1523 }
1524
1525 for(int s = 0; s < state.destSamples; s++)
1526 {
1527 if(!write(color, d, state))
1528 {
1529 return nullptr;
1530 }
1531
1532 d += *Pointer<Int>(blit + OFFSET(BlitData,dSliceB));
1533 }
1534 }
1535 }
1536 }
1537 }
1538
Ben Clayton056d6922019-07-04 12:41:13 +01001539 return function("BlitRoutine");
Nicolas Capens68a82382018-10-02 13:16:55 -04001540 }
1541
Ben Clayton6897e9b2019-07-16 17:27:27 +01001542 std::shared_ptr<Routine> Blitter::getBlitRoutine(const State &state)
Alexis Hetu33642272019-03-01 11:55:59 -05001543 {
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001544 std::unique_lock<std::mutex> lock(blitMutex);
Ben Clayton6897e9b2019-07-16 17:27:27 +01001545 auto blitRoutine = blitCache.query(state);
Alexis Hetu33642272019-03-01 11:55:59 -05001546
1547 if(!blitRoutine)
1548 {
1549 blitRoutine = generate(state);
1550
1551 if(!blitRoutine)
1552 {
Ben Clayton00424c12019-03-17 17:29:30 +00001553 UNIMPLEMENTED("blitRoutine");
Alexis Hetu33642272019-03-01 11:55:59 -05001554 return nullptr;
1555 }
1556
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001557 blitCache.add(state, blitRoutine);
Alexis Hetu33642272019-03-01 11:55:59 -05001558 }
1559
Alexis Hetu33642272019-03-01 11:55:59 -05001560 return blitRoutine;
1561 }
1562
Ben Clayton6897e9b2019-07-16 17:27:27 +01001563 std::shared_ptr<Routine> Blitter::getCornerUpdateRoutine(const State &state)
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001564 {
1565 std::unique_lock<std::mutex> lock(cornerUpdateMutex);
Ben Clayton6897e9b2019-07-16 17:27:27 +01001566 auto cornerUpdateRoutine = cornerUpdateCache.query(state);
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001567
1568 if(!cornerUpdateRoutine)
1569 {
1570 cornerUpdateRoutine = generateCornerUpdate(state);
1571
1572 if(!cornerUpdateRoutine)
1573 {
1574 UNIMPLEMENTED("cornerUpdateRoutine");
1575 return nullptr;
1576 }
1577
1578 cornerUpdateCache.add(state, cornerUpdateRoutine);
1579 }
1580
1581 return cornerUpdateRoutine;
1582 }
1583
Chris Forbes529eda32019-05-08 10:27:05 -07001584 void Blitter::blitToBuffer(const vk::Image *src, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *dst, int bufferRowPitch, int bufferSlicePitch)
1585 {
1586 auto aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
1587 auto format = src->getFormat(aspect);
1588 State state(format, format.getNonQuadLayoutFormat(), VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
1589 {false, false});
1590
Ben Clayton6897e9b2019-07-16 17:27:27 +01001591 auto blitRoutine = getBlitRoutine(state);
Chris Forbes529eda32019-05-08 10:27:05 -07001592 if(!blitRoutine)
1593 {
1594 return;
1595 }
1596
1597 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1598
1599 BlitData data =
1600 {
1601 nullptr, // source
1602 dst, // dest
1603 src->rowPitchBytes(aspect, subresource.mipLevel), // sPitchB
1604 bufferRowPitch, // dPitchB
1605 src->slicePitchBytes(aspect, subresource.mipLevel), // sSliceB
1606 bufferSlicePitch, // dSliceB
1607
1608 0, 0, 1, 1,
1609
1610 0, // y0d
1611 static_cast<int>(extent.height), // y1d
1612 0, // x0d
1613 static_cast<int>(extent.width), // x1d
1614
1615 static_cast<int>(extent.width), // sWidth
1616 static_cast<int>(extent.height) // sHeight;
1617 };
1618
1619 VkOffset3D srcOffset = { 0, 0, offset.z };
1620
1621 VkImageSubresourceLayers srcSubresLayers = subresource;
1622 srcSubresLayers.layerCount = 1;
1623
1624 VkImageSubresourceRange srcSubresRange =
1625 {
1626 subresource.aspectMask,
1627 subresource.mipLevel,
1628 1,
1629 subresource.baseArrayLayer,
1630 subresource.layerCount
1631 };
1632
1633 uint32_t lastLayer = src->getLastLayerIndex(srcSubresRange);
1634
1635 for(; srcSubresLayers.baseArrayLayer <= lastLayer; srcSubresLayers.baseArrayLayer++)
1636 {
1637 srcOffset.z = offset.z;
1638
1639 for(auto i = 0u; i < extent.depth; i++)
1640 {
1641 data.source = src->getTexelPointer(srcOffset, srcSubresLayers);
1642 ASSERT(data.source < src->end());
1643 blitFunction(&data);
1644 srcOffset.z++;
1645 data.dest = (dst += bufferSlicePitch);
1646 }
1647 }
1648 }
1649
1650 void Blitter::blitFromBuffer(const vk::Image *dst, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *src, int bufferRowPitch, int bufferSlicePitch)
1651 {
1652 auto aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
1653 auto format = dst->getFormat(aspect);
1654 State state(format.getNonQuadLayoutFormat(), format, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
1655 {false, false});
1656
Ben Clayton6897e9b2019-07-16 17:27:27 +01001657 auto blitRoutine = getBlitRoutine(state);
Chris Forbes529eda32019-05-08 10:27:05 -07001658 if(!blitRoutine)
1659 {
1660 return;
1661 }
1662
1663 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1664
1665 BlitData data =
1666 {
1667 src, // source
1668 nullptr, // dest
1669 bufferRowPitch, // sPitchB
1670 dst->rowPitchBytes(aspect, subresource.mipLevel), // dPitchB
1671 bufferSlicePitch, // sSliceB
1672 dst->slicePitchBytes(aspect, subresource.mipLevel), // dSliceB
1673
1674 0, 0, 1, 1,
1675
1676 offset.y, // y0d
1677 static_cast<int>(offset.y + extent.height), // y1d
1678 offset.x, // x0d
1679 static_cast<int>(offset.x + extent.width), // x1d
1680
1681 static_cast<int>(extent.width), // sWidth
1682 static_cast<int>(extent.height) // sHeight;
1683 };
1684
1685 VkOffset3D dstOffset = { 0, 0, offset.z };
1686
1687 VkImageSubresourceLayers dstSubresLayers = subresource;
1688 dstSubresLayers.layerCount = 1;
1689
1690 VkImageSubresourceRange dstSubresRange =
1691 {
1692 subresource.aspectMask,
1693 subresource.mipLevel,
1694 1,
1695 subresource.baseArrayLayer,
1696 subresource.layerCount
1697 };
1698
1699 uint32_t lastLayer = dst->getLastLayerIndex(dstSubresRange);
1700
1701 for(; dstSubresLayers.baseArrayLayer <= lastLayer; dstSubresLayers.baseArrayLayer++)
1702 {
1703 dstOffset.z = offset.z;
1704
1705 for(auto i = 0u; i < extent.depth; i++)
1706 {
1707 data.dest = dst->getTexelPointer(dstOffset, dstSubresLayers);
1708 ASSERT(data.dest < dst->end());
1709 blitFunction(&data);
1710 dstOffset.z++;
1711 data.source = (src += bufferSlicePitch);
1712 }
1713 }
1714 }
1715
Alexis Hetuac873342019-04-17 15:59:03 -04001716 void Blitter::blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter)
Alexis Hetu33642272019-03-01 11:55:59 -05001717 {
1718 if(dst->getFormat() == VK_FORMAT_UNDEFINED)
1719 {
1720 return;
1721 }
1722
Alexis Hetu377077a2019-03-14 15:10:51 -04001723 if((region.srcSubresource.layerCount != region.dstSubresource.layerCount) ||
Alexis Hetu33642272019-03-01 11:55:59 -05001724 (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask))
1725 {
Ben Clayton00424c12019-03-17 17:29:30 +00001726 UNIMPLEMENTED("region");
Alexis Hetu33642272019-03-01 11:55:59 -05001727 }
1728
1729 if(region.dstOffsets[0].x > region.dstOffsets[1].x)
1730 {
Nicolas Capensb8c63932019-03-19 01:52:40 -04001731 std::swap(region.srcOffsets[0].x, region.srcOffsets[1].x);
1732 std::swap(region.dstOffsets[0].x, region.dstOffsets[1].x);
Alexis Hetu33642272019-03-01 11:55:59 -05001733 }
1734
1735 if(region.dstOffsets[0].y > region.dstOffsets[1].y)
1736 {
Nicolas Capensb8c63932019-03-19 01:52:40 -04001737 std::swap(region.srcOffsets[0].y, region.srcOffsets[1].y);
1738 std::swap(region.dstOffsets[0].y, region.dstOffsets[1].y);
Alexis Hetu33642272019-03-01 11:55:59 -05001739 }
1740
Nicolas Capensba873302019-05-16 11:25:27 -04001741 VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask);
1742 VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask);
1743 VkExtent3D srcExtent = src->getMipLevelExtent(srcAspect, region.srcSubresource.mipLevel);
Alexis Hetu33642272019-03-01 11:55:59 -05001744
1745 int32_t numSlices = (region.srcOffsets[1].z - region.srcOffsets[0].z);
1746 ASSERT(numSlices == (region.dstOffsets[1].z - region.dstOffsets[0].z));
1747
Alexis Hetue24bc662019-03-21 18:04:29 -04001748 float widthRatio = static_cast<float>(region.srcOffsets[1].x - region.srcOffsets[0].x) /
1749 static_cast<float>(region.dstOffsets[1].x - region.dstOffsets[0].x);
1750 float heightRatio = static_cast<float>(region.srcOffsets[1].y - region.srcOffsets[0].y) /
1751 static_cast<float>(region.dstOffsets[1].y - region.dstOffsets[0].y);
1752 float x0 = region.srcOffsets[0].x + (0.5f - region.dstOffsets[0].x) * widthRatio;
1753 float y0 = region.srcOffsets[0].y + (0.5f - region.dstOffsets[0].y) * heightRatio;
1754
1755 bool doFilter = (filter != VK_FILTER_NEAREST);
Alexis Hetu54ec7592019-03-20 14:37:16 -04001756 State state(src->getFormat(srcAspect), dst->getFormat(dstAspect), src->getSampleCountFlagBits(), dst->getSampleCountFlagBits(),
Alexis Hetu3f80dad2019-05-22 18:23:47 -04001757 { doFilter, doFilter || (src->getSampleCountFlagBits() > 1) });
Alexis Hetu33642272019-03-01 11:55:59 -05001758 state.clampToEdge = (region.srcOffsets[0].x < 0) ||
1759 (region.srcOffsets[0].y < 0) ||
1760 (static_cast<uint32_t>(region.srcOffsets[1].x) > srcExtent.width) ||
Alexis Hetue24bc662019-03-21 18:04:29 -04001761 (static_cast<uint32_t>(region.srcOffsets[1].y) > srcExtent.height) ||
1762 (doFilter && ((x0 < 0.5f) || (y0 < 0.5f)));
Alexis Hetu33642272019-03-01 11:55:59 -05001763
Ben Clayton6897e9b2019-07-16 17:27:27 +01001764 auto blitRoutine = getBlitRoutine(state);
Alexis Hetu33642272019-03-01 11:55:59 -05001765 if(!blitRoutine)
1766 {
1767 return;
1768 }
1769
1770 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1771
Alexis Hetue24bc662019-03-21 18:04:29 -04001772 BlitData data =
1773 {
1774 nullptr, // source
1775 nullptr, // dest
1776 src->rowPitchBytes(srcAspect, region.srcSubresource.mipLevel), // sPitchB
1777 dst->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel), // dPitchB
Alexis Hetu54ec7592019-03-20 14:37:16 -04001778 src->slicePitchBytes(srcAspect, region.srcSubresource.mipLevel), // sSliceB
Alexis Hetue24bc662019-03-21 18:04:29 -04001779 dst->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel), // dSliceB
Alexis Hetu33642272019-03-01 11:55:59 -05001780
Alexis Hetue24bc662019-03-21 18:04:29 -04001781 x0,
1782 y0,
1783 widthRatio,
1784 heightRatio,
Alexis Hetu33642272019-03-01 11:55:59 -05001785
Alexis Hetue24bc662019-03-21 18:04:29 -04001786 region.dstOffsets[0].y, // y0d
1787 region.dstOffsets[1].y, // y1d
1788 region.dstOffsets[0].x, // x0d
1789 region.dstOffsets[1].x, // x1d
Alexis Hetu33642272019-03-01 11:55:59 -05001790
Alexis Hetue24bc662019-03-21 18:04:29 -04001791 static_cast<int>(srcExtent.width), // sWidth
1792 static_cast<int>(srcExtent.height) // sHeight;
1793 };
Alexis Hetu33642272019-03-01 11:55:59 -05001794
1795 VkOffset3D srcOffset = { 0, 0, region.srcOffsets[0].z };
1796 VkOffset3D dstOffset = { 0, 0, region.dstOffsets[0].z };
1797
Alexis Hetu377077a2019-03-14 15:10:51 -04001798 VkImageSubresourceLayers srcSubresLayers =
Alexis Hetu33642272019-03-01 11:55:59 -05001799 {
Alexis Hetu377077a2019-03-14 15:10:51 -04001800 region.srcSubresource.aspectMask,
1801 region.srcSubresource.mipLevel,
1802 region.srcSubresource.baseArrayLayer,
1803 1
1804 };
1805
1806 VkImageSubresourceLayers dstSubresLayers =
1807 {
1808 region.dstSubresource.aspectMask,
1809 region.dstSubresource.mipLevel,
1810 region.dstSubresource.baseArrayLayer,
1811 1
1812 };
1813
1814 VkImageSubresourceRange srcSubresRange =
1815 {
1816 region.srcSubresource.aspectMask,
1817 region.srcSubresource.mipLevel,
1818 1,
1819 region.srcSubresource.baseArrayLayer,
1820 region.srcSubresource.layerCount
1821 };
1822
1823 uint32_t lastLayer = src->getLastLayerIndex(srcSubresRange);
1824
1825 for(; srcSubresLayers.baseArrayLayer <= lastLayer; srcSubresLayers.baseArrayLayer++, dstSubresLayers.baseArrayLayer++)
1826 {
1827 srcOffset.z = region.srcOffsets[0].z;
1828 dstOffset.z = region.dstOffsets[0].z;
1829
1830 for(int i = 0; i < numSlices; i++)
1831 {
1832 data.source = src->getTexelPointer(srcOffset, srcSubresLayers);
1833 data.dest = dst->getTexelPointer(dstOffset, dstSubresLayers);
1834
1835 ASSERT(data.source < src->end());
1836 ASSERT(data.dest < dst->end());
1837
1838 blitFunction(&data);
1839 srcOffset.z++;
1840 dstOffset.z++;
1841 }
Alexis Hetu33642272019-03-01 11:55:59 -05001842 }
1843 }
Alexis Hetub317d962019-04-29 14:07:31 -04001844
1845 void Blitter::computeCubeCorner(Pointer<Byte>& layer, Int& x0, Int& x1, Int& y0, Int& y1, Int& pitchB, const State& state)
1846 {
1847 int bytes = state.sourceFormat.bytes();
1848 bool quadLayout = state.sourceFormat.hasQuadLayout();
1849
1850 Float4 c0;
1851 read(c0, layer + ComputeOffset(x0, y1, pitchB, bytes, quadLayout), state);
1852 Float4 c1;
1853 read(c1, layer + ComputeOffset(x1, y0, pitchB, bytes, quadLayout), state);
1854 c0 += c1;
1855 read(c1, layer + ComputeOffset(x1, y1, pitchB, bytes, quadLayout), state);
1856 c0 += c1;
1857 c0 *= Float4(1.0f / 3.0f);
1858 write(c0, layer + ComputeOffset(x0, y0, pitchB, bytes, quadLayout), state);
1859 }
1860
Ben Clayton6897e9b2019-07-16 17:27:27 +01001861 std::shared_ptr<Routine> Blitter::generateCornerUpdate(const State& state)
Alexis Hetub317d962019-04-29 14:07:31 -04001862 {
1863 // Reading and writing from/to the same image
1864 ASSERT(state.sourceFormat == state.destFormat);
1865 ASSERT(state.srcSamples == state.destSamples);
1866
1867 if(state.srcSamples != 1)
1868 {
1869 UNIMPLEMENTED("state.srcSamples %d", state.srcSamples);
1870 }
1871
1872 Function<Void(Pointer<Byte>)> function;
1873 {
1874 Pointer<Byte> blit(function.Arg<0>());
1875
1876 Pointer<Byte> layers = *Pointer<Pointer<Byte>>(blit + OFFSET(CubeBorderData, layers));
1877 Int pitchB = *Pointer<Int>(blit + OFFSET(CubeBorderData, pitchB));
1878 UInt layerSize = *Pointer<Int>(blit + OFFSET(CubeBorderData, layerSize));
1879 UInt dim = *Pointer<Int>(blit + OFFSET(CubeBorderData, dim));
1880
1881 // Low Border, Low Pixel, High Border, High Pixel
1882 Int LB(-1), LP(0), HB(dim), HP(dim-1);
1883
Nicolas Capensbb575d42019-05-31 15:36:59 -04001884 for(int face = 0; face < 6; face++)
Alexis Hetub317d962019-04-29 14:07:31 -04001885 {
1886 computeCubeCorner(layers, LB, LP, LB, LP, pitchB, state);
1887 computeCubeCorner(layers, LB, LP, HB, HP, pitchB, state);
1888 computeCubeCorner(layers, HB, HP, LB, LP, pitchB, state);
1889 computeCubeCorner(layers, HB, HP, HB, HP, pitchB, state);
1890 layers = layers + layerSize;
1891 }
1892 }
1893
Ben Clayton056d6922019-07-04 12:41:13 +01001894 return function("BlitRoutine");
Alexis Hetub317d962019-04-29 14:07:31 -04001895 }
1896
1897 void Blitter::updateBorders(vk::Image* image, const VkImageSubresourceLayers& subresourceLayers)
1898 {
1899 if(image->getArrayLayers() < (subresourceLayers.baseArrayLayer + 6))
1900 {
1901 UNIMPLEMENTED("image->getArrayLayers() %d, baseArrayLayer %d",
1902 image->getArrayLayers(), subresourceLayers.baseArrayLayer);
1903 }
1904
1905 // From Vulkan 1.1 spec, section 11.5. Image Views:
1906 // "For cube and cube array image views, the layers of the image view starting
1907 // at baseArrayLayer correspond to faces in the order +X, -X, +Y, -Y, +Z, -Z."
1908 VkImageSubresourceLayers posX = subresourceLayers;
1909 posX.layerCount = 1;
1910 VkImageSubresourceLayers negX = posX;
1911 negX.baseArrayLayer++;
1912 VkImageSubresourceLayers posY = negX;
1913 posY.baseArrayLayer++;
1914 VkImageSubresourceLayers negY = posY;
1915 negY.baseArrayLayer++;
1916 VkImageSubresourceLayers posZ = negY;
1917 posZ.baseArrayLayer++;
1918 VkImageSubresourceLayers negZ = posZ;
1919 negZ.baseArrayLayer++;
1920
1921 // Copy top / bottom
1922 copyCubeEdge(image, posX, BOTTOM, negY, RIGHT);
1923 copyCubeEdge(image, posY, BOTTOM, posZ, TOP);
1924 copyCubeEdge(image, posZ, BOTTOM, negY, TOP);
1925 copyCubeEdge(image, negX, BOTTOM, negY, LEFT);
1926 copyCubeEdge(image, negY, BOTTOM, negZ, BOTTOM);
1927 copyCubeEdge(image, negZ, BOTTOM, negY, BOTTOM);
1928
1929 copyCubeEdge(image, posX, TOP, posY, RIGHT);
1930 copyCubeEdge(image, posY, TOP, negZ, TOP);
1931 copyCubeEdge(image, posZ, TOP, posY, BOTTOM);
1932 copyCubeEdge(image, negX, TOP, posY, LEFT);
1933 copyCubeEdge(image, negY, TOP, posZ, BOTTOM);
1934 copyCubeEdge(image, negZ, TOP, posY, TOP);
1935
1936 // Copy left / right
1937 copyCubeEdge(image, posX, RIGHT, negZ, LEFT);
1938 copyCubeEdge(image, posY, RIGHT, posX, TOP);
1939 copyCubeEdge(image, posZ, RIGHT, posX, LEFT);
1940 copyCubeEdge(image, negX, RIGHT, posZ, LEFT);
1941 copyCubeEdge(image, negY, RIGHT, posX, BOTTOM);
1942 copyCubeEdge(image, negZ, RIGHT, negX, LEFT);
1943
1944 copyCubeEdge(image, posX, LEFT, posZ, RIGHT);
1945 copyCubeEdge(image, posY, LEFT, negX, TOP);
1946 copyCubeEdge(image, posZ, LEFT, negX, RIGHT);
1947 copyCubeEdge(image, negX, LEFT, negZ, RIGHT);
1948 copyCubeEdge(image, negY, LEFT, negX, BOTTOM);
1949 copyCubeEdge(image, negZ, LEFT, posX, RIGHT);
1950
1951 // Compute corner colors
1952 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceLayers.aspectMask);
1953 vk::Format format = image->getFormat(aspect);
1954 VkSampleCountFlagBits samples = image->getSampleCountFlagBits();
1955 State state(format, format, samples, samples, { 0xF });
1956
1957 if(samples != VK_SAMPLE_COUNT_1_BIT)
1958 {
1959 UNIMPLEMENTED("Multi-sampled cube: %d samples", static_cast<int>(samples));
1960 }
1961
Ben Clayton6897e9b2019-07-16 17:27:27 +01001962 auto cornerUpdateRoutine = getCornerUpdateRoutine(state);
Alexis Hetub317d962019-04-29 14:07:31 -04001963 if(!cornerUpdateRoutine)
1964 {
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001965 return;
Alexis Hetub317d962019-04-29 14:07:31 -04001966 }
1967
Alexis Hetub317d962019-04-29 14:07:31 -04001968 void(*cornerUpdateFunction)(const CubeBorderData *data) = (void(*)(const CubeBorderData*))cornerUpdateRoutine->getEntry();
1969
Nicolas Capensba873302019-05-16 11:25:27 -04001970 VkExtent3D extent = image->getMipLevelExtent(aspect, subresourceLayers.mipLevel);
Alexis Hetub317d962019-04-29 14:07:31 -04001971 CubeBorderData data =
1972 {
1973 image->getTexelPointer({ 0, 0, 0 }, posX),
1974 image->rowPitchBytes(aspect, subresourceLayers.mipLevel),
1975 static_cast<uint32_t>(image->getLayerSize(aspect)),
1976 extent.width
1977 };
1978 cornerUpdateFunction(&data);
1979 }
1980
1981 void Blitter::copyCubeEdge(vk::Image* image,
1982 const VkImageSubresourceLayers& dstSubresourceLayers, Edge dstEdge,
1983 const VkImageSubresourceLayers& srcSubresourceLayers, Edge srcEdge)
1984 {
1985 ASSERT(srcSubresourceLayers.aspectMask == dstSubresourceLayers.aspectMask);
1986 ASSERT(srcSubresourceLayers.mipLevel == dstSubresourceLayers.mipLevel);
1987 ASSERT(srcSubresourceLayers.baseArrayLayer != dstSubresourceLayers.baseArrayLayer);
1988 ASSERT(srcSubresourceLayers.layerCount == 1);
1989 ASSERT(dstSubresourceLayers.layerCount == 1);
1990
1991 // Figure out if the edges to be copied in reverse order respectively from one another
1992 // The copy should be reversed whenever the same edges are contiguous or if we're
1993 // copying top <-> right or bottom <-> left. This is explained by the layout, which is:
1994 //
1995 // | +y |
1996 // | -x | +z | +x | -z |
1997 // | -y |
1998
1999 bool reverse = (srcEdge == dstEdge) ||
2000 ((srcEdge == TOP) && (dstEdge == RIGHT)) ||
2001 ((srcEdge == RIGHT) && (dstEdge == TOP)) ||
2002 ((srcEdge == BOTTOM) && (dstEdge == LEFT)) ||
2003 ((srcEdge == LEFT) && (dstEdge == BOTTOM));
2004
2005 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(srcSubresourceLayers.aspectMask);
2006 int bytes = image->getFormat(aspect).bytes();
2007 int pitchB = image->rowPitchBytes(aspect, srcSubresourceLayers.mipLevel);
2008
Nicolas Capensba873302019-05-16 11:25:27 -04002009 VkExtent3D extent = image->getMipLevelExtent(aspect, srcSubresourceLayers.mipLevel);
Alexis Hetub317d962019-04-29 14:07:31 -04002010 int w = extent.width;
2011 int h = extent.height;
2012 if(w != h)
2013 {
2014 UNIMPLEMENTED("Cube doesn't have square faces : (%d, %d)", w, h);
2015 }
2016
2017 // Src is expressed in the regular [0, width-1], [0, height-1] space
2018 bool srcHorizontal = ((srcEdge == TOP) || (srcEdge == BOTTOM));
2019 int srcDelta = srcHorizontal ? bytes : pitchB;
2020 VkOffset3D srcOffset = { (srcEdge == RIGHT) ? (w - 1) : 0, (srcEdge == BOTTOM) ? (h - 1) : 0, 0 };
2021
2022 // Dst contains borders, so it is expressed in the [-1, width], [-1, height] space
2023 bool dstHorizontal = ((dstEdge == TOP) || (dstEdge == BOTTOM));
2024 int dstDelta = (dstHorizontal ? bytes : pitchB) * (reverse ? -1 : 1);
2025 VkOffset3D dstOffset = { (dstEdge == RIGHT) ? w : -1, (dstEdge == BOTTOM) ? h : -1, 0 };
2026
2027 // Don't write in the corners
2028 if(dstHorizontal)
2029 {
2030 dstOffset.x += reverse ? w : 1;
2031 }
2032 else
2033 {
2034 dstOffset.y += reverse ? h : 1;
2035 }
2036
2037 const uint8_t* src = static_cast<const uint8_t*>(image->getTexelPointer(srcOffset, srcSubresourceLayers));
2038 uint8_t *dst = static_cast<uint8_t*>(image->getTexelPointer(dstOffset, dstSubresourceLayers));
2039 ASSERT((src < image->end()) && ((src + (w * srcDelta)) < image->end()));
2040 ASSERT((dst < image->end()) && ((dst + (w * dstDelta)) < image->end()));
2041
2042 for(int i = 0; i < w; ++i, dst += dstDelta, src += srcDelta)
2043 {
2044 memcpy(dst, src, bytes);
2045 }
2046 }
Nicolas Capens68a82382018-10-02 13:16:55 -04002047}