blob: f6d714fa793597f7ebe0500b10b98daa1c9e5675 [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 });
Ben Clayton6897e9b2019-07-16 17:27:27 +010055 auto 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 Hetu126bd7a2019-05-10 17:07:42 -0400234 sw::clear((uint16_t*)d, static_cast<uint16_t>(packed), area.extent.width);
Alexis Hetu33642272019-03-01 11:55:59 -0500235 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:
Hernan Liatis762741b2019-06-26 17:57:55 -0700278 case VK_FORMAT_R8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400279 c.x = Float(Int(*Pointer<Byte>(element)));
280 c.w = float(0xFF);
281 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500282 case VK_FORMAT_R16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400283 c.x = Float(Int(*Pointer<Short>(element)));
284 c.w = float(0x7FFF);
285 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500286 case VK_FORMAT_R16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400287 c.x = Float(Int(*Pointer<UShort>(element)));
288 c.w = float(0xFFFF);
289 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500290 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400291 c.x = Float(*Pointer<Int>(element));
292 c.w = float(0x7FFFFFFF);
293 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500294 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400295 c.x = Float(*Pointer<UInt>(element));
296 c.w = float(0xFFFFFFFF);
297 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500298 case VK_FORMAT_B8G8R8A8_SRGB:
Alexis Hetudd152e12018-11-14 13:39:28 -0500299 case VK_FORMAT_B8G8R8A8_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400300 c = Float4(*Pointer<Byte4>(element)).zyxw;
301 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500302 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500303 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500304 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500305 case VK_FORMAT_R8G8B8A8_SNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400306 c = Float4(*Pointer<SByte4>(element));
307 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500308 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
309 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500310 case VK_FORMAT_R8G8B8A8_UNORM:
311 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500312 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500313 case VK_FORMAT_R8G8B8A8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400314 c = Float4(*Pointer<Byte4>(element));
315 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500316 case VK_FORMAT_R16G16B16A16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400317 c = Float4(*Pointer<Short4>(element));
318 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500319 case VK_FORMAT_R16G16B16A16_UNORM:
320 case VK_FORMAT_R16G16B16A16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400321 c = Float4(*Pointer<UShort4>(element));
322 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500323 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400324 c = Float4(*Pointer<Int4>(element));
325 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500326 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400327 c = Float4(*Pointer<UInt4>(element));
328 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500329 case VK_FORMAT_R8G8_SINT:
330 case VK_FORMAT_R8G8_SNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400331 c.x = Float(Int(*Pointer<SByte>(element + 0)));
332 c.y = Float(Int(*Pointer<SByte>(element + 1)));
333 c.w = float(0x7F);
334 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500335 case VK_FORMAT_R8G8_UNORM:
336 case VK_FORMAT_R8G8_UINT:
Alexis Hetu45d34d22019-06-28 15:58:54 -0400337 case VK_FORMAT_R8G8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400338 c.x = Float(Int(*Pointer<Byte>(element + 0)));
339 c.y = Float(Int(*Pointer<Byte>(element + 1)));
340 c.w = float(0xFF);
341 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500342 case VK_FORMAT_R16G16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400343 c.x = Float(Int(*Pointer<Short>(element + 0)));
344 c.y = Float(Int(*Pointer<Short>(element + 2)));
345 c.w = float(0x7FFF);
346 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500347 case VK_FORMAT_R16G16_UNORM:
348 case VK_FORMAT_R16G16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400349 c.x = Float(Int(*Pointer<UShort>(element + 0)));
350 c.y = Float(Int(*Pointer<UShort>(element + 2)));
351 c.w = float(0xFFFF);
352 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500353 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400354 c.x = Float(*Pointer<Int>(element + 0));
355 c.y = Float(*Pointer<Int>(element + 4));
356 c.w = float(0x7FFFFFFF);
357 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500358 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400359 c.x = Float(*Pointer<UInt>(element + 0));
360 c.y = Float(*Pointer<UInt>(element + 4));
361 c.w = float(0xFFFFFFFF);
362 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500363 case VK_FORMAT_R32G32B32A32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400364 c = *Pointer<Float4>(element);
365 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500366 case VK_FORMAT_R32G32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400367 c.x = *Pointer<Float>(element + 0);
368 c.y = *Pointer<Float>(element + 4);
369 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500370 case VK_FORMAT_R32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400371 c.x = *Pointer<Float>(element);
372 break;
Ben Clayton00424c12019-03-17 17:29:30 +0000373 case VK_FORMAT_R16G16B16A16_SFLOAT:
374 c.w = Float(*Pointer<Half>(element + 6));
375 case VK_FORMAT_R16G16B16_SFLOAT:
376 c.z = Float(*Pointer<Half>(element + 4));
377 case VK_FORMAT_R16G16_SFLOAT:
378 c.y = Float(*Pointer<Half>(element + 2));
379 case VK_FORMAT_R16_SFLOAT:
380 c.x = Float(*Pointer<Half>(element));
Alexis Hetu734e2572018-12-20 14:00:49 -0500381 break;
Alexis Hetu5131ec92018-12-20 16:14:21 -0500382 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
383 // 10 (or 11) bit float formats are unsigned formats with a 5 bit exponent and a 5 (or 6) bit mantissa.
384 // Since the Half float format also has a 5 bit exponent, we can convert these formats to half by
385 // copy/pasting the bits so the the exponent bits and top mantissa bits are aligned to the half format.
386 // In this case, we have:
387 // 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
388 // 1st Short: |xxxxxxxxxx---------------------|
389 // 2nd Short: |xxxx---------------------xxxxxx|
390 // 3rd Short: |--------------------xxxxxxxxxxxx|
391 // These memory reads overlap, but each of them contains an entire channel, so we can read this without
392 // any int -> short conversion.
393 c.x = Float(As<Half>((*Pointer<UShort>(element + 0) & UShort(0x07FF)) << UShort(4)));
394 c.y = Float(As<Half>((*Pointer<UShort>(element + 1) & UShort(0x3FF8)) << UShort(1)));
395 c.z = Float(As<Half>((*Pointer<UShort>(element + 2) & UShort(0xFFC0)) >> UShort(1)));
396 break;
397 case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
398 // 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 +0000399 c.x = Float(*Pointer<UInt>(element) & UInt(0x000001FF)); // R's mantissa (bits 0-8)
400 c.y = Float((*Pointer<UInt>(element) & UInt(0x0003FE00)) >> 9); // G's mantissa (bits 9-17)
Alexis Hetu5131ec92018-12-20 16:14:21 -0500401 c.z = Float((*Pointer<UInt>(element) & UInt(0x07FC0000)) >> 18); // B's mantissa (bits 18-26)
402 c *= Float4(
403 // 2^E, using the exponent (bits 27-31) and treating it as an unsigned integer value
404 Float(UInt(1) << ((*Pointer<UInt>(element) & UInt(0xF8000000)) >> 27)) *
405 // Since the 9 bit mantissa values currently stored in RGB were converted straight
406 // from int to float (in the [0, 1<<9] range instead of the [0, 1] range), they
407 // are (1 << 9) times too high.
408 // Also, the exponent has 5 bits and we compute the exponent bias of floating point
409 // formats using "2^(k-1) - 1", so, in this case, the exponent bias is 2^(5-1)-1 = 15
410 // Exponent bias (15) + number of mantissa bits per component (9) = 24
411 Float(1.0f / (1 << 24)));
412 c.w = 1.0f;
413 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500414 case VK_FORMAT_R5G6B5_UNORM_PACK16:
Nicolas Capens68a82382018-10-02 13:16:55 -0400415 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
416 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07E0)) >> UShort(5)));
417 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
418 break;
Alexis Hetu457bd9b2018-12-20 13:18:18 -0500419 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
420 c.w = Float(Int((*Pointer<UShort>(element) & UShort(0x8000)) >> UShort(15)));
421 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0x7C00)) >> UShort(10)));
422 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x03E0)) >> UShort(5)));
423 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
424 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500425 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
426 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400427 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
428 c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
429 c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
430 c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
431 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500432 case VK_FORMAT_D16_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400433 c.x = Float(Int((*Pointer<UShort>(element))));
434 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500435 case VK_FORMAT_D24_UNORM_S8_UINT:
436 case VK_FORMAT_X8_D24_UNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400437 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0xFFFFFF00)) >> 8));
438 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500439 case VK_FORMAT_D32_SFLOAT:
440 case VK_FORMAT_D32_SFLOAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400441 c.x = *Pointer<Float>(element);
442 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500443 case VK_FORMAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400444 c.x = Float(Int(*Pointer<Byte>(element)));
445 break;
446 default:
447 return false;
448 }
449
450 return true;
451 }
452
453 bool Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
454 {
455 bool writeR = state.writeRed;
456 bool writeG = state.writeGreen;
457 bool writeB = state.writeBlue;
458 bool writeA = state.writeAlpha;
459 bool writeRGBA = writeR && writeG && writeB && writeA;
460
461 switch(state.destFormat)
462 {
Alexis Hetue04d9b02019-01-16 14:42:24 -0500463 case VK_FORMAT_R4G4_UNORM_PACK8:
464 if(writeR | writeG)
465 {
466 if(!writeR)
467 {
468 *Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
469 (*Pointer<Byte>(element) & Byte(0xF0));
470 }
471 else if(!writeG)
472 {
473 *Pointer<Byte>(element) = (*Pointer<Byte>(element) & Byte(0xF)) |
474 (Byte(RoundInt(Float(c.x))) << Byte(4));
475 }
476 else
477 {
478 *Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
479 (Byte(RoundInt(Float(c.x))) << Byte(4));
480 }
481 }
482 break;
483 case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
484 if(writeR || writeG || writeB || writeA)
485 {
486 *Pointer<UShort>(element) = (writeR ? ((UShort(RoundInt(Float(c.x))) & UShort(0xF)) << UShort(12)) :
487 (*Pointer<UShort>(element) & UShort(0x000F))) |
488 (writeG ? ((UShort(RoundInt(Float(c.y))) & UShort(0xF)) << UShort(8)) :
489 (*Pointer<UShort>(element) & UShort(0x00F0))) |
490 (writeB ? ((UShort(RoundInt(Float(c.z))) & UShort(0xF)) << UShort(4)) :
491 (*Pointer<UShort>(element) & UShort(0x0F00))) |
492 (writeA ? (UShort(RoundInt(Float(c.w))) & UShort(0xF)) :
493 (*Pointer<UShort>(element) & UShort(0xF000)));
494 }
495 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500496 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
497 if(writeRGBA)
498 {
Ben Clayton00424c12019-03-17 17:29:30 +0000499 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) & Int(0xF)) |
500 UShort((RoundInt(Float(c.x)) & Int(0xF)) << 4) |
501 UShort((RoundInt(Float(c.y)) & Int(0xF)) << 8) |
502 UShort((RoundInt(Float(c.z)) & Int(0xF)) << 12);
Alexis Hetua28671d2018-12-19 17:23:26 -0500503 }
504 else
505 {
506 unsigned short mask = (writeA ? 0x000F : 0x0000) |
507 (writeR ? 0x00F0 : 0x0000) |
508 (writeG ? 0x0F00 : 0x0000) |
509 (writeB ? 0xF000 : 0x0000);
510 unsigned short unmask = ~mask;
511 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
Ben Clayton00424c12019-03-17 17:29:30 +0000512 ((UShort(RoundInt(Float(c.w)) & Int(0xF)) |
513 UShort((RoundInt(Float(c.x)) & Int(0xF)) << 4) |
514 UShort((RoundInt(Float(c.y)) & Int(0xF)) << 8) |
Alexis Hetua28671d2018-12-19 17:23:26 -0500515 UShort((RoundInt(Float(c.z)) & Int(0xF)) << 12)) & UShort(mask));
516 }
517 break;
518 case VK_FORMAT_B8G8R8A8_SRGB:
Alexis Hetudd152e12018-11-14 13:39:28 -0500519 case VK_FORMAT_B8G8R8A8_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400520 if(writeRGBA)
521 {
522 Short4 c0 = RoundShort4(c.zyxw);
523 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
524 }
525 else
526 {
527 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
528 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
529 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
530 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
531 }
532 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500533 case VK_FORMAT_B8G8R8_SNORM:
534 if(writeB) { *Pointer<SByte>(element + 0) = SByte(RoundInt(Float(c.z))); }
535 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
536 if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
537 break;
538 case VK_FORMAT_B8G8R8_UNORM:
539 case VK_FORMAT_B8G8R8_SRGB:
540 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
541 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
542 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
543 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500544 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500545 case VK_FORMAT_R8G8B8A8_UNORM:
Alexis Hetua28671d2018-12-19 17:23:26 -0500546 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500547 case VK_FORMAT_R8G8B8A8_SRGB:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500548 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
549 case VK_FORMAT_R8G8B8A8_UINT:
550 case VK_FORMAT_R8G8B8A8_USCALED:
551 case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400552 if(writeRGBA)
553 {
554 Short4 c0 = RoundShort4(c);
555 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
556 }
557 else
558 {
559 if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
560 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
561 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
562 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
563 }
564 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500565 case VK_FORMAT_R32G32B32A32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400566 if(writeRGBA)
567 {
568 *Pointer<Float4>(element) = c;
569 }
570 else
571 {
572 if(writeR) { *Pointer<Float>(element) = c.x; }
573 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
574 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
575 if(writeA) { *Pointer<Float>(element + 12) = c.w; }
576 }
577 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500578 case VK_FORMAT_R32G32B32_SFLOAT:
579 if(writeR) { *Pointer<Float>(element) = c.x; }
580 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
581 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
582 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500583 case VK_FORMAT_R32G32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400584 if(writeR && writeG)
585 {
586 *Pointer<Float2>(element) = Float2(c);
587 }
588 else
589 {
590 if(writeR) { *Pointer<Float>(element) = c.x; }
591 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
592 }
593 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500594 case VK_FORMAT_R32_SFLOAT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400595 if(writeR) { *Pointer<Float>(element) = c.x; }
596 break;
Ben Clayton00424c12019-03-17 17:29:30 +0000597 case VK_FORMAT_R16G16B16A16_SFLOAT:
598 if(writeA) { *Pointer<Half>(element + 6) = Half(c.w); }
599 case VK_FORMAT_R16G16B16_SFLOAT:
600 if(writeB) { *Pointer<Half>(element + 4) = Half(c.z); }
601 case VK_FORMAT_R16G16_SFLOAT:
602 if(writeG) { *Pointer<Half>(element + 2) = Half(c.y); }
603 case VK_FORMAT_R16_SFLOAT:
604 if(writeR) { *Pointer<Half>(element) = Half(c.x); }
Alexis Hetu734e2572018-12-20 14:00:49 -0500605 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500606 case VK_FORMAT_B8G8R8A8_SNORM:
607 if(writeB) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.z))); }
608 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
609 if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
610 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
611 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500612 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500613 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetua28671d2018-12-19 17:23:26 -0500614 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500615 case VK_FORMAT_R8G8B8A8_SNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500616 case VK_FORMAT_R8G8B8A8_SSCALED:
617 case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400618 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
Alexis Hetue04d9b02019-01-16 14:42:24 -0500619 case VK_FORMAT_R8G8B8_SINT:
620 case VK_FORMAT_R8G8B8_SNORM:
621 case VK_FORMAT_R8G8B8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400622 if(writeB) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.z))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500623 case VK_FORMAT_R8G8_SINT:
624 case VK_FORMAT_R8G8_SNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500625 case VK_FORMAT_R8G8_SSCALED:
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:
Nicolas Capens68a82382018-10-02 13:16:55 -0400630 if(writeR) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.x))); }
631 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500632 case VK_FORMAT_R8G8B8_UINT:
633 case VK_FORMAT_R8G8B8_UNORM:
634 case VK_FORMAT_R8G8B8_USCALED:
Alexis Hetu45d34d22019-06-28 15:58:54 -0400635 case VK_FORMAT_R8G8B8_SRGB:
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:
Alexis Hetu45d34d22019-06-28 15:58:54 -0400640 case VK_FORMAT_R8G8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400641 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500642 case VK_FORMAT_R8_UINT:
643 case VK_FORMAT_R8_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500644 case VK_FORMAT_R8_USCALED:
Hernan Liatis762741b2019-06-26 17:57:55 -0700645 case VK_FORMAT_R8_SRGB:
Nicolas Capens68a82382018-10-02 13:16:55 -0400646 if(writeR) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x))); }
647 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500648 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500649 case VK_FORMAT_R16G16B16A16_SNORM:
650 case VK_FORMAT_R16G16B16A16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400651 if(writeRGBA)
652 {
653 *Pointer<Short4>(element) = Short4(RoundInt(c));
654 }
655 else
656 {
657 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
658 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
659 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
660 if(writeA) { *Pointer<Short>(element + 6) = Short(RoundInt(Float(c.w))); }
661 }
662 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500663 case VK_FORMAT_R16G16B16_SINT:
664 case VK_FORMAT_R16G16B16_SNORM:
665 case VK_FORMAT_R16G16B16_SSCALED:
666 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
667 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
668 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
669 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500670 case VK_FORMAT_R16G16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500671 case VK_FORMAT_R16G16_SNORM:
672 case VK_FORMAT_R16G16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400673 if(writeR && writeG)
674 {
675 *Pointer<Short2>(element) = Short2(Short4(RoundInt(c)));
676 }
677 else
678 {
679 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
680 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
681 }
682 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500683 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500684 case VK_FORMAT_R16_SNORM:
685 case VK_FORMAT_R16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400686 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
687 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500688 case VK_FORMAT_R16G16B16A16_UINT:
689 case VK_FORMAT_R16G16B16A16_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500690 case VK_FORMAT_R16G16B16A16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400691 if(writeRGBA)
692 {
693 *Pointer<UShort4>(element) = UShort4(RoundInt(c));
694 }
695 else
696 {
697 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
698 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
699 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
700 if(writeA) { *Pointer<UShort>(element + 6) = UShort(RoundInt(Float(c.w))); }
701 }
702 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500703 case VK_FORMAT_R16G16B16_UINT:
704 case VK_FORMAT_R16G16B16_UNORM:
705 case VK_FORMAT_R16G16B16_USCALED:
706 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
707 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
708 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
709 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500710 case VK_FORMAT_R16G16_UINT:
711 case VK_FORMAT_R16G16_UNORM:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500712 case VK_FORMAT_R16G16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400713 if(writeR && writeG)
714 {
715 *Pointer<UShort2>(element) = UShort2(UShort4(RoundInt(c)));
716 }
717 else
718 {
719 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
720 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
721 }
722 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500723 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500724 case VK_FORMAT_R16_UNORM:
725 case VK_FORMAT_R16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -0400726 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
727 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500728 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400729 if(writeRGBA)
730 {
731 *Pointer<Int4>(element) = RoundInt(c);
732 }
733 else
734 {
735 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
736 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
737 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
738 if(writeA) { *Pointer<Int>(element + 12) = RoundInt(Float(c.w)); }
739 }
740 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500741 case VK_FORMAT_R32G32B32_SINT:
742 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500743 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400744 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500745 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400746 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
747 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500748 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400749 if(writeRGBA)
750 {
751 *Pointer<UInt4>(element) = UInt4(RoundInt(c));
752 }
753 else
754 {
755 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
756 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
757 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
758 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(RoundInt(Float(c.w))); }
759 }
760 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500761 case VK_FORMAT_R32G32B32_UINT:
762 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500763 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400764 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
Alexis Hetudd152e12018-11-14 13:39:28 -0500765 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400766 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
767 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500768 case VK_FORMAT_R5G6B5_UNORM_PACK16:
Nicolas Capens68a82382018-10-02 13:16:55 -0400769 if(writeR && writeG && writeB)
770 {
771 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.z)) |
772 (RoundInt(Float(c.y)) << Int(5)) |
773 (RoundInt(Float(c.x)) << Int(11)));
774 }
775 else
776 {
777 unsigned short mask = (writeB ? 0x001F : 0x0000) | (writeG ? 0x07E0 : 0x0000) | (writeR ? 0xF800 : 0x0000);
778 unsigned short unmask = ~mask;
779 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
780 (UShort(RoundInt(Float(c.z)) |
781 (RoundInt(Float(c.y)) << Int(5)) |
782 (RoundInt(Float(c.x)) << Int(11))) & UShort(mask));
783 }
784 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500785 case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
786 if(writeRGBA)
787 {
788 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) |
789 (RoundInt(Float(c.z)) << Int(1)) |
790 (RoundInt(Float(c.y)) << Int(6)) |
791 (RoundInt(Float(c.x)) << Int(11)));
792 }
793 else
794 {
795 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
796 (writeR ? 0x7C00 : 0x0000) |
797 (writeG ? 0x03E0 : 0x0000) |
798 (writeB ? 0x001F : 0x0000);
799 unsigned short unmask = ~mask;
800 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
801 (UShort(RoundInt(Float(c.w)) |
802 (RoundInt(Float(c.z)) << Int(1)) |
803 (RoundInt(Float(c.y)) << Int(6)) |
804 (RoundInt(Float(c.x)) << Int(11))) & UShort(mask));
805 }
806 break;
807 case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
808 if(writeRGBA)
809 {
810 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) |
811 (RoundInt(Float(c.x)) << Int(1)) |
812 (RoundInt(Float(c.y)) << Int(6)) |
813 (RoundInt(Float(c.z)) << Int(11)));
814 }
815 else
816 {
817 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
818 (writeR ? 0x7C00 : 0x0000) |
819 (writeG ? 0x03E0 : 0x0000) |
820 (writeB ? 0x001F : 0x0000);
821 unsigned short unmask = ~mask;
822 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
823 (UShort(RoundInt(Float(c.w)) |
824 (RoundInt(Float(c.x)) << Int(1)) |
825 (RoundInt(Float(c.y)) << Int(6)) |
826 (RoundInt(Float(c.z)) << Int(11))) & UShort(mask));
827 }
828 break;
Alexis Hetu457bd9b2018-12-20 13:18:18 -0500829 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
830 if(writeRGBA)
831 {
832 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.z)) |
833 (RoundInt(Float(c.y)) << Int(5)) |
834 (RoundInt(Float(c.x)) << Int(10)) |
835 (RoundInt(Float(c.w)) << Int(15)));
836 }
837 else
838 {
839 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
840 (writeR ? 0x7C00 : 0x0000) |
841 (writeG ? 0x03E0 : 0x0000) |
842 (writeB ? 0x001F : 0x0000);
843 unsigned short unmask = ~mask;
844 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
845 (UShort(RoundInt(Float(c.z)) |
846 (RoundInt(Float(c.y)) << Int(5)) |
847 (RoundInt(Float(c.x)) << Int(10)) |
848 (RoundInt(Float(c.w)) << Int(15))) & UShort(mask));
849 }
850 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500851 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
852 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500853 case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400854 if(writeRGBA)
855 {
856 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) |
857 (RoundInt(Float(c.y)) << 10) |
858 (RoundInt(Float(c.z)) << 20) |
859 (RoundInt(Float(c.w)) << 30));
860 }
861 else
862 {
863 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
864 (writeB ? 0x3FF00000 : 0x0000) |
865 (writeG ? 0x000FFC00 : 0x0000) |
866 (writeR ? 0x000003FF : 0x0000);
867 unsigned int unmask = ~mask;
868 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
869 (UInt(RoundInt(Float(c.x)) |
Alexis Hetua28671d2018-12-19 17:23:26 -0500870 (RoundInt(Float(c.y)) << 10) |
871 (RoundInt(Float(c.z)) << 20) |
872 (RoundInt(Float(c.w)) << 30)) & UInt(mask));
Nicolas Capens68a82382018-10-02 13:16:55 -0400873 }
874 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -0500875 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
876 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
877 case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
878 if(writeRGBA)
879 {
880 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.z)) |
881 (RoundInt(Float(c.y)) << 10) |
882 (RoundInt(Float(c.x)) << 20) |
883 (RoundInt(Float(c.w)) << 30));
884 }
885 else
886 {
887 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
888 (writeR ? 0x3FF00000 : 0x0000) |
889 (writeG ? 0x000FFC00 : 0x0000) |
890 (writeB ? 0x000003FF : 0x0000);
891 unsigned int unmask = ~mask;
892 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
893 (UInt(RoundInt(Float(c.z)) |
894 (RoundInt(Float(c.y)) << 10) |
895 (RoundInt(Float(c.x)) << 20) |
896 (RoundInt(Float(c.w)) << 30)) & UInt(mask));
897 }
898 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500899 case VK_FORMAT_D16_UNORM:
Nicolas Capens68a82382018-10-02 13:16:55 -0400900 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x)));
901 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500902 case VK_FORMAT_D24_UNORM_S8_UINT:
903 case VK_FORMAT_X8_D24_UNORM_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -0400904 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) << 8);
905 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500906 case VK_FORMAT_D32_SFLOAT:
907 case VK_FORMAT_D32_SFLOAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400908 *Pointer<Float>(element) = c.x;
909 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500910 case VK_FORMAT_S8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400911 *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
912 break;
913 default:
914 return false;
915 }
916 return true;
917 }
918
919 bool Blitter::read(Int4 &c, Pointer<Byte> element, const State &state)
920 {
921 c = Int4(0, 0, 0, 1);
922
923 switch(state.sourceFormat)
924 {
Alexis Hetua28671d2018-12-19 17:23:26 -0500925 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500926 case VK_FORMAT_R8G8B8A8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400927 c = Insert(c, Int(*Pointer<SByte>(element + 3)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500928 c = Insert(c, Int(*Pointer<SByte>(element + 2)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500929 case VK_FORMAT_R8G8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400930 c = Insert(c, Int(*Pointer<SByte>(element + 1)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500931 case VK_FORMAT_R8_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400932 c = Insert(c, Int(*Pointer<SByte>(element)), 0);
933 break;
Alexis Hetua28671d2018-12-19 17:23:26 -0500934 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
935 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000003FF))), 0);
936 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10), 1);
937 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20), 2);
938 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30), 3);
939 break;
940 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -0500941 case VK_FORMAT_R8G8B8A8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400942 c = Insert(c, Int(*Pointer<Byte>(element + 3)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500943 c = Insert(c, Int(*Pointer<Byte>(element + 2)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500944 case VK_FORMAT_R8G8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400945 c = Insert(c, Int(*Pointer<Byte>(element + 1)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500946 case VK_FORMAT_R8_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400947 c = Insert(c, Int(*Pointer<Byte>(element)), 0);
948 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500949 case VK_FORMAT_R16G16B16A16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400950 c = Insert(c, Int(*Pointer<Short>(element + 6)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500951 c = Insert(c, Int(*Pointer<Short>(element + 4)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500952 case VK_FORMAT_R16G16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400953 c = Insert(c, Int(*Pointer<Short>(element + 2)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500954 case VK_FORMAT_R16_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400955 c = Insert(c, Int(*Pointer<Short>(element)), 0);
956 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500957 case VK_FORMAT_R16G16B16A16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400958 c = Insert(c, Int(*Pointer<UShort>(element + 6)), 3);
Alexis Hetua28671d2018-12-19 17:23:26 -0500959 c = Insert(c, Int(*Pointer<UShort>(element + 4)), 2);
Alexis Hetudd152e12018-11-14 13:39:28 -0500960 case VK_FORMAT_R16G16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400961 c = Insert(c, Int(*Pointer<UShort>(element + 2)), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500962 case VK_FORMAT_R16_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400963 c = Insert(c, Int(*Pointer<UShort>(element)), 0);
964 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500965 case VK_FORMAT_R32G32B32A32_SINT:
966 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400967 c = *Pointer<Int4>(element);
968 break;
Alexis Hetudd152e12018-11-14 13:39:28 -0500969 case VK_FORMAT_R32G32_SINT:
970 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400971 c = Insert(c, *Pointer<Int>(element + 4), 1);
Alexis Hetudd152e12018-11-14 13:39:28 -0500972 case VK_FORMAT_R32_SINT:
973 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -0400974 c = Insert(c, *Pointer<Int>(element), 0);
975 break;
976 default:
977 return false;
978 }
979
980 return true;
981 }
982
983 bool Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
984 {
985 bool writeR = state.writeRed;
986 bool writeG = state.writeGreen;
987 bool writeB = state.writeBlue;
988 bool writeA = state.writeAlpha;
989 bool writeRGBA = writeR && writeG && writeB && writeA;
990
991 switch(state.destFormat)
992 {
Alexis Hetu6d8d3c32018-12-21 12:03:31 -0500993 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
994 c = Min(As<UInt4>(c), UInt4(0x03FF, 0x03FF, 0x03FF, 0x0003));
995 break;
996 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
997 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -0500998 case VK_FORMAT_R8G8B8_UINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -0500999 case VK_FORMAT_R8G8_UINT:
1000 case VK_FORMAT_R8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001001 case VK_FORMAT_R8G8B8A8_USCALED:
1002 case VK_FORMAT_R8G8B8_USCALED:
1003 case VK_FORMAT_R8G8_USCALED:
1004 case VK_FORMAT_R8_USCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001005 c = Min(As<UInt4>(c), UInt4(0xFF));
1006 break;
1007 case VK_FORMAT_R16G16B16A16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001008 case VK_FORMAT_R16G16B16_UINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001009 case VK_FORMAT_R16G16_UINT:
1010 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001011 case VK_FORMAT_R16G16B16A16_USCALED:
1012 case VK_FORMAT_R16G16B16_USCALED:
1013 case VK_FORMAT_R16G16_USCALED:
1014 case VK_FORMAT_R16_USCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001015 c = Min(As<UInt4>(c), UInt4(0xFFFF));
1016 break;
1017 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1018 case VK_FORMAT_R8G8B8A8_SINT:
1019 case VK_FORMAT_R8G8_SINT:
1020 case VK_FORMAT_R8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001021 case VK_FORMAT_R8G8B8A8_SSCALED:
1022 case VK_FORMAT_R8G8B8_SSCALED:
1023 case VK_FORMAT_R8G8_SSCALED:
1024 case VK_FORMAT_R8_SSCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001025 c = Min(Max(c, Int4(-0x80)), Int4(0x7F));
1026 break;
1027 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001028 case VK_FORMAT_R16G16B16_SINT:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001029 case VK_FORMAT_R16G16_SINT:
1030 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001031 case VK_FORMAT_R16G16B16A16_SSCALED:
1032 case VK_FORMAT_R16G16B16_SSCALED:
1033 case VK_FORMAT_R16G16_SSCALED:
1034 case VK_FORMAT_R16_SSCALED:
Alexis Hetu6d8d3c32018-12-21 12:03:31 -05001035 c = Min(Max(c, Int4(-0x8000)), Int4(0x7FFF));
1036 break;
1037 default:
1038 break;
1039 }
1040
1041 switch(state.destFormat)
1042 {
Alexis Hetue04d9b02019-01-16 14:42:24 -05001043 case VK_FORMAT_B8G8R8A8_SINT:
1044 case VK_FORMAT_B8G8R8A8_SSCALED:
1045 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
1046 case VK_FORMAT_B8G8R8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001047 case VK_FORMAT_B8G8R8_SSCALED:
1048 if(writeB) { *Pointer<SByte>(element) = SByte(Extract(c, 2)); }
1049 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
1050 if(writeR) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 0)); }
1051 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001052 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -05001053 case VK_FORMAT_R8G8B8A8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001054 case VK_FORMAT_R8G8B8A8_SSCALED:
1055 case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -04001056 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001057 case VK_FORMAT_R8G8B8_SINT:
1058 case VK_FORMAT_R8G8B8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001059 if(writeB) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001060 case VK_FORMAT_R8G8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001061 case VK_FORMAT_R8G8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001062 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001063 case VK_FORMAT_R8_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001064 case VK_FORMAT_R8_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001065 if(writeR) { *Pointer<SByte>(element) = SByte(Extract(c, 0)); }
1066 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001067 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001068 case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1069 case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
1070 case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
Alexis Hetua28671d2018-12-19 17:23:26 -05001071 if(writeRGBA)
1072 {
1073 *Pointer<UInt>(element) =
1074 UInt((Extract(c, 0)) | (Extract(c, 1) << 10) | (Extract(c, 2) << 20) | (Extract(c, 3) << 30));
1075 }
1076 else
1077 {
1078 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1079 (writeB ? 0x3FF00000 : 0x0000) |
1080 (writeG ? 0x000FFC00 : 0x0000) |
1081 (writeR ? 0x000003FF : 0x0000);
1082 unsigned int unmask = ~mask;
1083 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1084 (UInt(Extract(c, 0) | (Extract(c, 1) << 10) | (Extract(c, 2) << 20) | (Extract(c, 3) << 30)) & UInt(mask));
1085 }
1086 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001087 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1088 case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1089 case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
1090 case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
1091 if(writeRGBA)
1092 {
1093 *Pointer<UInt>(element) =
1094 UInt((Extract(c, 2)) | (Extract(c, 1) << 10) | (Extract(c, 0) << 20) | (Extract(c, 3) << 30));
1095 }
1096 else
1097 {
1098 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1099 (writeR ? 0x3FF00000 : 0x0000) |
1100 (writeG ? 0x000FFC00 : 0x0000) |
1101 (writeB ? 0x000003FF : 0x0000);
1102 unsigned int unmask = ~mask;
1103 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
1104 (UInt(Extract(c, 2) | (Extract(c, 1) << 10) | (Extract(c, 0) << 20) | (Extract(c, 3) << 30)) & UInt(mask));
1105 }
1106 break;
1107 case VK_FORMAT_B8G8R8A8_UINT:
1108 case VK_FORMAT_B8G8R8A8_USCALED:
1109 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
1110 case VK_FORMAT_B8G8R8_UINT:
1111 case VK_FORMAT_B8G8R8_USCALED:
Alexis Hetu45d34d22019-06-28 15:58:54 -04001112 case VK_FORMAT_B8G8R8_SRGB:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001113 if(writeB) { *Pointer<Byte>(element) = Byte(Extract(c, 2)); }
1114 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
1115 if(writeR) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 0)); }
1116 break;
Alexis Hetua28671d2018-12-19 17:23:26 -05001117 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
Alexis Hetudd152e12018-11-14 13:39:28 -05001118 case VK_FORMAT_R8G8B8A8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001119 case VK_FORMAT_R8G8B8A8_USCALED:
1120 case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
Nicolas Capens68a82382018-10-02 13:16:55 -04001121 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001122 case VK_FORMAT_R8G8B8_UINT:
1123 case VK_FORMAT_R8G8B8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001124 if(writeB) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001125 case VK_FORMAT_R8G8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001126 case VK_FORMAT_R8G8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001127 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001128 case VK_FORMAT_R8_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001129 case VK_FORMAT_R8_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001130 if(writeR) { *Pointer<Byte>(element) = Byte(Extract(c, 0)); }
1131 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001132 case VK_FORMAT_R16G16B16A16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001133 case VK_FORMAT_R16G16B16A16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001134 if(writeA) { *Pointer<Short>(element + 6) = Short(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001135 case VK_FORMAT_R16G16B16_SINT:
1136 case VK_FORMAT_R16G16B16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001137 if(writeB) { *Pointer<Short>(element + 4) = Short(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001138 case VK_FORMAT_R16G16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001139 case VK_FORMAT_R16G16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001140 if(writeG) { *Pointer<Short>(element + 2) = Short(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001141 case VK_FORMAT_R16_SINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001142 case VK_FORMAT_R16_SSCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001143 if(writeR) { *Pointer<Short>(element) = Short(Extract(c, 0)); }
1144 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001145 case VK_FORMAT_R16G16B16A16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001146 case VK_FORMAT_R16G16B16A16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001147 if(writeA) { *Pointer<UShort>(element + 6) = UShort(Extract(c, 3)); }
Alexis Hetue04d9b02019-01-16 14:42:24 -05001148 case VK_FORMAT_R16G16B16_UINT:
1149 case VK_FORMAT_R16G16B16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001150 if(writeB) { *Pointer<UShort>(element + 4) = UShort(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001151 case VK_FORMAT_R16G16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001152 case VK_FORMAT_R16G16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001153 if(writeG) { *Pointer<UShort>(element + 2) = UShort(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001154 case VK_FORMAT_R16_UINT:
Alexis Hetue04d9b02019-01-16 14:42:24 -05001155 case VK_FORMAT_R16_USCALED:
Nicolas Capens68a82382018-10-02 13:16:55 -04001156 if(writeR) { *Pointer<UShort>(element) = UShort(Extract(c, 0)); }
1157 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001158 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001159 if(writeRGBA)
1160 {
1161 *Pointer<Int4>(element) = c;
1162 }
1163 else
1164 {
1165 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1166 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1167 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1168 if(writeA) { *Pointer<Int>(element + 12) = Extract(c, 3); }
1169 }
1170 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001171 case VK_FORMAT_R32G32B32_SINT:
1172 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1173 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1174 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1175 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001176 case VK_FORMAT_R32G32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001177 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1178 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1179 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001180 case VK_FORMAT_R32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001181 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1182 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001183 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001184 if(writeRGBA)
1185 {
1186 *Pointer<UInt4>(element) = As<UInt4>(c);
1187 }
1188 else
1189 {
1190 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1191 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
1192 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
1193 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(Extract(c, 3)); }
1194 }
1195 break;
Alexis Hetue04d9b02019-01-16 14:42:24 -05001196 case VK_FORMAT_R32G32B32_UINT:
1197 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001198 case VK_FORMAT_R32G32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001199 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
Alexis Hetudd152e12018-11-14 13:39:28 -05001200 case VK_FORMAT_R32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001201 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1202 break;
1203 default:
1204 return false;
1205 }
1206
1207 return true;
1208 }
1209
Nicolas Capens68a82382018-10-02 13:16:55 -04001210 bool Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
1211 {
1212 float4 scale, unscale;
1213 if(state.clearOperation &&
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001214 state.sourceFormat.isNonNormalizedInteger() &&
1215 !state.destFormat.isNonNormalizedInteger())
Nicolas Capens68a82382018-10-02 13:16:55 -04001216 {
1217 // If we're clearing a buffer from an int or uint color into a normalized color,
1218 // then the whole range of the int or uint color must be scaled between 0 and 1.
1219 switch(state.sourceFormat)
1220 {
Alexis Hetudd152e12018-11-14 13:39:28 -05001221 case VK_FORMAT_R32G32B32A32_SINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001222 unscale = replicate(static_cast<float>(0x7FFFFFFF));
1223 break;
Alexis Hetudd152e12018-11-14 13:39:28 -05001224 case VK_FORMAT_R32G32B32A32_UINT:
Nicolas Capens68a82382018-10-02 13:16:55 -04001225 unscale = replicate(static_cast<float>(0xFFFFFFFF));
1226 break;
1227 default:
1228 return false;
1229 }
1230 }
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001231 else if(!state.sourceFormat.getScale(unscale))
Nicolas Capens68a82382018-10-02 13:16:55 -04001232 {
1233 return false;
1234 }
1235
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001236 if(!state.destFormat.getScale(scale))
Nicolas Capens68a82382018-10-02 13:16:55 -04001237 {
1238 return false;
1239 }
1240
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001241 bool srcSRGB = state.sourceFormat.isSRGBformat();
1242 bool dstSRGB = state.destFormat.isSRGBformat();
Nicolas Capens68a82382018-10-02 13:16:55 -04001243
1244 if(state.convertSRGB && ((srcSRGB && !preScaled) || dstSRGB)) // One of the formats is sRGB encoded.
1245 {
1246 value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) : // Unapply scale
1247 Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w); // Apply unscale
1248 value = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : LinearToSRGB(value);
1249 value *= Float4(scale.x, scale.y, scale.z, scale.w); // Apply scale
1250 }
1251 else if(unscale != scale)
1252 {
1253 value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
1254 }
1255
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001256 if(state.sourceFormat.isFloatFormat() && !state.destFormat.isFloatFormat())
Nicolas Capens68a82382018-10-02 13:16:55 -04001257 {
1258 value = Min(value, Float4(scale.x, scale.y, scale.z, scale.w));
1259
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001260 value = Max(value, Float4(state.destFormat.isUnsignedComponent(0) ? 0.0f : -scale.x,
1261 state.destFormat.isUnsignedComponent(1) ? 0.0f : -scale.y,
1262 state.destFormat.isUnsignedComponent(2) ? 0.0f : -scale.z,
1263 state.destFormat.isUnsignedComponent(3) ? 0.0f : -scale.w));
Nicolas Capens68a82382018-10-02 13:16:55 -04001264 }
1265
1266 return true;
1267 }
1268
1269 Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout)
1270 {
1271 if(!quadLayout)
1272 {
1273 return y * pitchB + x * bytes;
1274 }
1275 else
1276 {
1277 // (x & ~1) * 2 + (x & 1) == (x - (x & 1)) * 2 + (x & 1) == x * 2 - (x & 1) * 2 + (x & 1) == x * 2 - (x & 1)
1278 return (y & Int(~1)) * pitchB +
1279 ((y & Int(1)) * 2 + x * 2 - (x & Int(1))) * bytes;
1280 }
1281 }
1282
1283 Float4 Blitter::LinearToSRGB(Float4 &c)
1284 {
1285 Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
1286 Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
1287
1288 Float4 s = c;
1289 s.xyz = Max(lc, ec);
1290
1291 return s;
1292 }
1293
1294 Float4 Blitter::sRGBtoLinear(Float4 &c)
1295 {
1296 Float4 lc = c * Float4(1.0f / 12.92f);
1297 Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
1298
1299 Int4 linear = CmpLT(c, Float4(0.04045f));
1300
1301 Float4 s = c;
Ben Clayton5e9441a2019-05-24 07:43:42 +01001302 s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec))); // TODO: IfThenElse()
Nicolas Capens68a82382018-10-02 13:16:55 -04001303
1304 return s;
1305 }
1306
Ben Clayton6897e9b2019-07-16 17:27:27 +01001307 std::shared_ptr<Routine> Blitter::generate(const State &state)
Nicolas Capens68a82382018-10-02 13:16:55 -04001308 {
1309 Function<Void(Pointer<Byte>)> function;
1310 {
1311 Pointer<Byte> blit(function.Arg<0>());
1312
1313 Pointer<Byte> source = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,source));
1314 Pointer<Byte> dest = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,dest));
1315 Int sPitchB = *Pointer<Int>(blit + OFFSET(BlitData,sPitchB));
1316 Int dPitchB = *Pointer<Int>(blit + OFFSET(BlitData,dPitchB));
1317
1318 Float x0 = *Pointer<Float>(blit + OFFSET(BlitData,x0));
1319 Float y0 = *Pointer<Float>(blit + OFFSET(BlitData,y0));
1320 Float w = *Pointer<Float>(blit + OFFSET(BlitData,w));
1321 Float h = *Pointer<Float>(blit + OFFSET(BlitData,h));
1322
1323 Int x0d = *Pointer<Int>(blit + OFFSET(BlitData,x0d));
1324 Int x1d = *Pointer<Int>(blit + OFFSET(BlitData,x1d));
1325 Int y0d = *Pointer<Int>(blit + OFFSET(BlitData,y0d));
1326 Int y1d = *Pointer<Int>(blit + OFFSET(BlitData,y1d));
1327
1328 Int sWidth = *Pointer<Int>(blit + OFFSET(BlitData,sWidth));
1329 Int sHeight = *Pointer<Int>(blit + OFFSET(BlitData,sHeight));
1330
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001331 bool intSrc = state.sourceFormat.isNonNormalizedInteger();
1332 bool intDst = state.destFormat.isNonNormalizedInteger();
Nicolas Capens68a82382018-10-02 13:16:55 -04001333 bool intBoth = intSrc && intDst;
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001334 bool srcQuadLayout = state.sourceFormat.hasQuadLayout();
1335 bool dstQuadLayout = state.destFormat.hasQuadLayout();
1336 int srcBytes = state.sourceFormat.bytes();
1337 int dstBytes = state.destFormat.bytes();
Nicolas Capens68a82382018-10-02 13:16:55 -04001338
1339 bool hasConstantColorI = false;
1340 Int4 constantColorI;
1341 bool hasConstantColorF = false;
1342 Float4 constantColorF;
1343 if(state.clearOperation)
1344 {
1345 if(intBoth) // Integer types
1346 {
1347 if(!read(constantColorI, source, state))
1348 {
1349 return nullptr;
1350 }
1351 hasConstantColorI = true;
1352 }
1353 else
1354 {
1355 if(!read(constantColorF, source, state))
1356 {
1357 return nullptr;
1358 }
1359 hasConstantColorF = true;
1360
1361 if(!ApplyScaleAndClamp(constantColorF, state))
1362 {
1363 return nullptr;
1364 }
1365 }
1366 }
1367
1368 For(Int j = y0d, j < y1d, j++)
1369 {
1370 Float y = state.clearOperation ? RValue<Float>(y0) : y0 + Float(j) * h;
1371 Pointer<Byte> destLine = dest + (dstQuadLayout ? j & Int(~1) : RValue<Int>(j)) * dPitchB;
1372
1373 For(Int i = x0d, i < x1d, i++)
1374 {
1375 Float x = state.clearOperation ? RValue<Float>(x0) : x0 + Float(i) * w;
1376 Pointer<Byte> d = destLine + (dstQuadLayout ? (((j & Int(1)) << 1) + (i * 2) - (i & Int(1))) : RValue<Int>(i)) * dstBytes;
1377
1378 if(hasConstantColorI)
1379 {
1380 if(!write(constantColorI, d, state))
1381 {
1382 return nullptr;
1383 }
1384 }
1385 else if(hasConstantColorF)
1386 {
1387 for(int s = 0; s < state.destSamples; s++)
1388 {
1389 if(!write(constantColorF, d, state))
1390 {
1391 return nullptr;
1392 }
1393
1394 d += *Pointer<Int>(blit + OFFSET(BlitData, dSliceB));
1395 }
1396 }
1397 else if(intBoth) // Integer types do not support filtering
1398 {
1399 Int4 color; // When both formats are true integer types, we don't go to float to avoid losing precision
1400 Int X = Int(x);
1401 Int Y = Int(y);
1402
1403 if(state.clampToEdge)
1404 {
1405 X = Clamp(X, 0, sWidth - 1);
1406 Y = Clamp(Y, 0, sHeight - 1);
1407 }
1408
1409 Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1410
1411 if(!read(color, s, state))
1412 {
1413 return nullptr;
1414 }
1415
1416 if(!write(color, d, state))
1417 {
1418 return nullptr;
1419 }
1420 }
1421 else
1422 {
1423 Float4 color;
1424
1425 bool preScaled = false;
1426 if(!state.filter || intSrc)
1427 {
1428 Int X = Int(x);
1429 Int Y = Int(y);
1430
1431 if(state.clampToEdge)
1432 {
1433 X = Clamp(X, 0, sWidth - 1);
1434 Y = Clamp(Y, 0, sHeight - 1);
1435 }
1436
1437 Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1438
1439 if(!read(color, s, state))
1440 {
1441 return nullptr;
1442 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001443
1444 if(state.srcSamples > 1) // Resolve multisampled source
1445 {
Alexis Hetua4308132019-06-13 09:55:26 -04001446 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1447 {
1448 if(!ApplyScaleAndClamp(color, state)) return nullptr;
1449 preScaled = true;
1450 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001451 Float4 accum = color;
Alexis Hetu126bd7a2019-05-10 17:07:42 -04001452 for(int sample = 1; sample < state.srcSamples; sample++)
Alexis Hetu54ec7592019-03-20 14:37:16 -04001453 {
1454 s += *Pointer<Int>(blit + OFFSET(BlitData, sSliceB));
1455 if(!read(color, s, state))
1456 {
1457 return nullptr;
1458 }
Alexis Hetu3f80dad2019-05-22 18:23:47 -04001459 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1460 {
1461 if(!ApplyScaleAndClamp(color, state)) return nullptr;
1462 preScaled = true;
1463 }
Alexis Hetu54ec7592019-03-20 14:37:16 -04001464 accum += color;
1465 }
1466 color = accum * Float4(1.0f / static_cast<float>(state.srcSamples));
1467 }
Nicolas Capens68a82382018-10-02 13:16:55 -04001468 }
1469 else // Bilinear filtering
1470 {
1471 Float X = x;
1472 Float Y = y;
1473
1474 if(state.clampToEdge)
1475 {
1476 X = Min(Max(x, 0.5f), Float(sWidth) - 0.5f);
1477 Y = Min(Max(y, 0.5f), Float(sHeight) - 0.5f);
1478 }
1479
1480 Float x0 = X - 0.5f;
1481 Float y0 = Y - 0.5f;
1482
1483 Int X0 = Max(Int(x0), 0);
1484 Int Y0 = Max(Int(y0), 0);
1485
1486 Int X1 = X0 + 1;
1487 Int Y1 = Y0 + 1;
1488 X1 = IfThenElse(X1 >= sWidth, X0, X1);
1489 Y1 = IfThenElse(Y1 >= sHeight, Y0, Y1);
1490
1491 Pointer<Byte> s00 = source + ComputeOffset(X0, Y0, sPitchB, srcBytes, srcQuadLayout);
1492 Pointer<Byte> s01 = source + ComputeOffset(X1, Y0, sPitchB, srcBytes, srcQuadLayout);
1493 Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, sPitchB, srcBytes, srcQuadLayout);
1494 Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, sPitchB, srcBytes, srcQuadLayout);
1495
1496 Float4 c00; if(!read(c00, s00, state)) return nullptr;
1497 Float4 c01; if(!read(c01, s01, state)) return nullptr;
1498 Float4 c10; if(!read(c10, s10, state)) return nullptr;
1499 Float4 c11; if(!read(c11, s11, state)) return nullptr;
1500
Alexis Hetu25ec7b02019-03-12 14:19:22 -04001501 if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
Nicolas Capens68a82382018-10-02 13:16:55 -04001502 {
1503 if(!ApplyScaleAndClamp(c00, state)) return nullptr;
1504 if(!ApplyScaleAndClamp(c01, state)) return nullptr;
1505 if(!ApplyScaleAndClamp(c10, state)) return nullptr;
1506 if(!ApplyScaleAndClamp(c11, state)) return nullptr;
1507 preScaled = true;
1508 }
1509
1510 Float4 fx = Float4(x0 - Float(X0));
1511 Float4 fy = Float4(y0 - Float(Y0));
1512 Float4 ix = Float4(1.0f) - fx;
1513 Float4 iy = Float4(1.0f) - fy;
1514
1515 color = (c00 * ix + c01 * fx) * iy +
1516 (c10 * ix + c11 * fx) * fy;
1517 }
1518
1519 if(!ApplyScaleAndClamp(color, state, preScaled))
1520 {
1521 return nullptr;
1522 }
1523
1524 for(int s = 0; s < state.destSamples; s++)
1525 {
1526 if(!write(color, d, state))
1527 {
1528 return nullptr;
1529 }
1530
1531 d += *Pointer<Int>(blit + OFFSET(BlitData,dSliceB));
1532 }
1533 }
1534 }
1535 }
1536 }
1537
Ben Clayton056d6922019-07-04 12:41:13 +01001538 return function("BlitRoutine");
Nicolas Capens68a82382018-10-02 13:16:55 -04001539 }
1540
Ben Clayton6897e9b2019-07-16 17:27:27 +01001541 std::shared_ptr<Routine> Blitter::getBlitRoutine(const State &state)
Alexis Hetu33642272019-03-01 11:55:59 -05001542 {
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001543 std::unique_lock<std::mutex> lock(blitMutex);
Ben Clayton6897e9b2019-07-16 17:27:27 +01001544 auto blitRoutine = blitCache.query(state);
Alexis Hetu33642272019-03-01 11:55:59 -05001545
1546 if(!blitRoutine)
1547 {
1548 blitRoutine = generate(state);
1549
1550 if(!blitRoutine)
1551 {
Ben Clayton00424c12019-03-17 17:29:30 +00001552 UNIMPLEMENTED("blitRoutine");
Alexis Hetu33642272019-03-01 11:55:59 -05001553 return nullptr;
1554 }
1555
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001556 blitCache.add(state, blitRoutine);
Alexis Hetu33642272019-03-01 11:55:59 -05001557 }
1558
Alexis Hetu33642272019-03-01 11:55:59 -05001559 return blitRoutine;
1560 }
1561
Ben Clayton6897e9b2019-07-16 17:27:27 +01001562 std::shared_ptr<Routine> Blitter::getCornerUpdateRoutine(const State &state)
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001563 {
1564 std::unique_lock<std::mutex> lock(cornerUpdateMutex);
Ben Clayton6897e9b2019-07-16 17:27:27 +01001565 auto cornerUpdateRoutine = cornerUpdateCache.query(state);
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001566
1567 if(!cornerUpdateRoutine)
1568 {
1569 cornerUpdateRoutine = generateCornerUpdate(state);
1570
1571 if(!cornerUpdateRoutine)
1572 {
1573 UNIMPLEMENTED("cornerUpdateRoutine");
1574 return nullptr;
1575 }
1576
1577 cornerUpdateCache.add(state, cornerUpdateRoutine);
1578 }
1579
1580 return cornerUpdateRoutine;
1581 }
1582
Chris Forbes529eda32019-05-08 10:27:05 -07001583 void Blitter::blitToBuffer(const vk::Image *src, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *dst, int bufferRowPitch, int bufferSlicePitch)
1584 {
1585 auto aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
1586 auto format = src->getFormat(aspect);
1587 State state(format, format.getNonQuadLayoutFormat(), VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
1588 {false, false});
1589
Ben Clayton6897e9b2019-07-16 17:27:27 +01001590 auto blitRoutine = getBlitRoutine(state);
Chris Forbes529eda32019-05-08 10:27:05 -07001591 if(!blitRoutine)
1592 {
1593 return;
1594 }
1595
1596 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1597
1598 BlitData data =
1599 {
1600 nullptr, // source
1601 dst, // dest
1602 src->rowPitchBytes(aspect, subresource.mipLevel), // sPitchB
1603 bufferRowPitch, // dPitchB
1604 src->slicePitchBytes(aspect, subresource.mipLevel), // sSliceB
1605 bufferSlicePitch, // dSliceB
1606
1607 0, 0, 1, 1,
1608
1609 0, // y0d
1610 static_cast<int>(extent.height), // y1d
1611 0, // x0d
1612 static_cast<int>(extent.width), // x1d
1613
1614 static_cast<int>(extent.width), // sWidth
1615 static_cast<int>(extent.height) // sHeight;
1616 };
1617
1618 VkOffset3D srcOffset = { 0, 0, offset.z };
1619
1620 VkImageSubresourceLayers srcSubresLayers = subresource;
1621 srcSubresLayers.layerCount = 1;
1622
1623 VkImageSubresourceRange srcSubresRange =
1624 {
1625 subresource.aspectMask,
1626 subresource.mipLevel,
1627 1,
1628 subresource.baseArrayLayer,
1629 subresource.layerCount
1630 };
1631
1632 uint32_t lastLayer = src->getLastLayerIndex(srcSubresRange);
1633
1634 for(; srcSubresLayers.baseArrayLayer <= lastLayer; srcSubresLayers.baseArrayLayer++)
1635 {
1636 srcOffset.z = offset.z;
1637
1638 for(auto i = 0u; i < extent.depth; i++)
1639 {
1640 data.source = src->getTexelPointer(srcOffset, srcSubresLayers);
1641 ASSERT(data.source < src->end());
1642 blitFunction(&data);
1643 srcOffset.z++;
1644 data.dest = (dst += bufferSlicePitch);
1645 }
1646 }
1647 }
1648
1649 void Blitter::blitFromBuffer(const vk::Image *dst, VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t *src, int bufferRowPitch, int bufferSlicePitch)
1650 {
1651 auto aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
1652 auto format = dst->getFormat(aspect);
1653 State state(format.getNonQuadLayoutFormat(), format, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
1654 {false, false});
1655
Ben Clayton6897e9b2019-07-16 17:27:27 +01001656 auto blitRoutine = getBlitRoutine(state);
Chris Forbes529eda32019-05-08 10:27:05 -07001657 if(!blitRoutine)
1658 {
1659 return;
1660 }
1661
1662 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1663
1664 BlitData data =
1665 {
1666 src, // source
1667 nullptr, // dest
1668 bufferRowPitch, // sPitchB
1669 dst->rowPitchBytes(aspect, subresource.mipLevel), // dPitchB
1670 bufferSlicePitch, // sSliceB
1671 dst->slicePitchBytes(aspect, subresource.mipLevel), // dSliceB
1672
1673 0, 0, 1, 1,
1674
1675 offset.y, // y0d
1676 static_cast<int>(offset.y + extent.height), // y1d
1677 offset.x, // x0d
1678 static_cast<int>(offset.x + extent.width), // x1d
1679
1680 static_cast<int>(extent.width), // sWidth
1681 static_cast<int>(extent.height) // sHeight;
1682 };
1683
1684 VkOffset3D dstOffset = { 0, 0, offset.z };
1685
1686 VkImageSubresourceLayers dstSubresLayers = subresource;
1687 dstSubresLayers.layerCount = 1;
1688
1689 VkImageSubresourceRange dstSubresRange =
1690 {
1691 subresource.aspectMask,
1692 subresource.mipLevel,
1693 1,
1694 subresource.baseArrayLayer,
1695 subresource.layerCount
1696 };
1697
1698 uint32_t lastLayer = dst->getLastLayerIndex(dstSubresRange);
1699
1700 for(; dstSubresLayers.baseArrayLayer <= lastLayer; dstSubresLayers.baseArrayLayer++)
1701 {
1702 dstOffset.z = offset.z;
1703
1704 for(auto i = 0u; i < extent.depth; i++)
1705 {
1706 data.dest = dst->getTexelPointer(dstOffset, dstSubresLayers);
1707 ASSERT(data.dest < dst->end());
1708 blitFunction(&data);
1709 dstOffset.z++;
1710 data.source = (src += bufferSlicePitch);
1711 }
1712 }
1713 }
1714
Alexis Hetuac873342019-04-17 15:59:03 -04001715 void Blitter::blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter)
Alexis Hetu33642272019-03-01 11:55:59 -05001716 {
1717 if(dst->getFormat() == VK_FORMAT_UNDEFINED)
1718 {
1719 return;
1720 }
1721
Alexis Hetu377077a2019-03-14 15:10:51 -04001722 if((region.srcSubresource.layerCount != region.dstSubresource.layerCount) ||
Alexis Hetu33642272019-03-01 11:55:59 -05001723 (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask))
1724 {
Ben Clayton00424c12019-03-17 17:29:30 +00001725 UNIMPLEMENTED("region");
Alexis Hetu33642272019-03-01 11:55:59 -05001726 }
1727
1728 if(region.dstOffsets[0].x > region.dstOffsets[1].x)
1729 {
Nicolas Capensb8c63932019-03-19 01:52:40 -04001730 std::swap(region.srcOffsets[0].x, region.srcOffsets[1].x);
1731 std::swap(region.dstOffsets[0].x, region.dstOffsets[1].x);
Alexis Hetu33642272019-03-01 11:55:59 -05001732 }
1733
1734 if(region.dstOffsets[0].y > region.dstOffsets[1].y)
1735 {
Nicolas Capensb8c63932019-03-19 01:52:40 -04001736 std::swap(region.srcOffsets[0].y, region.srcOffsets[1].y);
1737 std::swap(region.dstOffsets[0].y, region.dstOffsets[1].y);
Alexis Hetu33642272019-03-01 11:55:59 -05001738 }
1739
Nicolas Capensba873302019-05-16 11:25:27 -04001740 VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask);
1741 VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask);
1742 VkExtent3D srcExtent = src->getMipLevelExtent(srcAspect, region.srcSubresource.mipLevel);
Alexis Hetu33642272019-03-01 11:55:59 -05001743
1744 int32_t numSlices = (region.srcOffsets[1].z - region.srcOffsets[0].z);
1745 ASSERT(numSlices == (region.dstOffsets[1].z - region.dstOffsets[0].z));
1746
Alexis Hetue24bc662019-03-21 18:04:29 -04001747 float widthRatio = static_cast<float>(region.srcOffsets[1].x - region.srcOffsets[0].x) /
1748 static_cast<float>(region.dstOffsets[1].x - region.dstOffsets[0].x);
1749 float heightRatio = static_cast<float>(region.srcOffsets[1].y - region.srcOffsets[0].y) /
1750 static_cast<float>(region.dstOffsets[1].y - region.dstOffsets[0].y);
1751 float x0 = region.srcOffsets[0].x + (0.5f - region.dstOffsets[0].x) * widthRatio;
1752 float y0 = region.srcOffsets[0].y + (0.5f - region.dstOffsets[0].y) * heightRatio;
1753
1754 bool doFilter = (filter != VK_FILTER_NEAREST);
Alexis Hetu54ec7592019-03-20 14:37:16 -04001755 State state(src->getFormat(srcAspect), dst->getFormat(dstAspect), src->getSampleCountFlagBits(), dst->getSampleCountFlagBits(),
Alexis Hetu3f80dad2019-05-22 18:23:47 -04001756 { doFilter, doFilter || (src->getSampleCountFlagBits() > 1) });
Alexis Hetu33642272019-03-01 11:55:59 -05001757 state.clampToEdge = (region.srcOffsets[0].x < 0) ||
1758 (region.srcOffsets[0].y < 0) ||
1759 (static_cast<uint32_t>(region.srcOffsets[1].x) > srcExtent.width) ||
Alexis Hetue24bc662019-03-21 18:04:29 -04001760 (static_cast<uint32_t>(region.srcOffsets[1].y) > srcExtent.height) ||
1761 (doFilter && ((x0 < 0.5f) || (y0 < 0.5f)));
Alexis Hetu33642272019-03-01 11:55:59 -05001762
Ben Clayton6897e9b2019-07-16 17:27:27 +01001763 auto blitRoutine = getBlitRoutine(state);
Alexis Hetu33642272019-03-01 11:55:59 -05001764 if(!blitRoutine)
1765 {
1766 return;
1767 }
1768
1769 void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1770
Alexis Hetue24bc662019-03-21 18:04:29 -04001771 BlitData data =
1772 {
1773 nullptr, // source
1774 nullptr, // dest
1775 src->rowPitchBytes(srcAspect, region.srcSubresource.mipLevel), // sPitchB
1776 dst->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel), // dPitchB
Alexis Hetu54ec7592019-03-20 14:37:16 -04001777 src->slicePitchBytes(srcAspect, region.srcSubresource.mipLevel), // sSliceB
Alexis Hetue24bc662019-03-21 18:04:29 -04001778 dst->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel), // dSliceB
Alexis Hetu33642272019-03-01 11:55:59 -05001779
Alexis Hetue24bc662019-03-21 18:04:29 -04001780 x0,
1781 y0,
1782 widthRatio,
1783 heightRatio,
Alexis Hetu33642272019-03-01 11:55:59 -05001784
Alexis Hetue24bc662019-03-21 18:04:29 -04001785 region.dstOffsets[0].y, // y0d
1786 region.dstOffsets[1].y, // y1d
1787 region.dstOffsets[0].x, // x0d
1788 region.dstOffsets[1].x, // x1d
Alexis Hetu33642272019-03-01 11:55:59 -05001789
Alexis Hetue24bc662019-03-21 18:04:29 -04001790 static_cast<int>(srcExtent.width), // sWidth
1791 static_cast<int>(srcExtent.height) // sHeight;
1792 };
Alexis Hetu33642272019-03-01 11:55:59 -05001793
1794 VkOffset3D srcOffset = { 0, 0, region.srcOffsets[0].z };
1795 VkOffset3D dstOffset = { 0, 0, region.dstOffsets[0].z };
1796
Alexis Hetu377077a2019-03-14 15:10:51 -04001797 VkImageSubresourceLayers srcSubresLayers =
Alexis Hetu33642272019-03-01 11:55:59 -05001798 {
Alexis Hetu377077a2019-03-14 15:10:51 -04001799 region.srcSubresource.aspectMask,
1800 region.srcSubresource.mipLevel,
1801 region.srcSubresource.baseArrayLayer,
1802 1
1803 };
1804
1805 VkImageSubresourceLayers dstSubresLayers =
1806 {
1807 region.dstSubresource.aspectMask,
1808 region.dstSubresource.mipLevel,
1809 region.dstSubresource.baseArrayLayer,
1810 1
1811 };
1812
1813 VkImageSubresourceRange srcSubresRange =
1814 {
1815 region.srcSubresource.aspectMask,
1816 region.srcSubresource.mipLevel,
1817 1,
1818 region.srcSubresource.baseArrayLayer,
1819 region.srcSubresource.layerCount
1820 };
1821
1822 uint32_t lastLayer = src->getLastLayerIndex(srcSubresRange);
1823
1824 for(; srcSubresLayers.baseArrayLayer <= lastLayer; srcSubresLayers.baseArrayLayer++, dstSubresLayers.baseArrayLayer++)
1825 {
1826 srcOffset.z = region.srcOffsets[0].z;
1827 dstOffset.z = region.dstOffsets[0].z;
1828
1829 for(int i = 0; i < numSlices; i++)
1830 {
1831 data.source = src->getTexelPointer(srcOffset, srcSubresLayers);
1832 data.dest = dst->getTexelPointer(dstOffset, dstSubresLayers);
1833
1834 ASSERT(data.source < src->end());
1835 ASSERT(data.dest < dst->end());
1836
1837 blitFunction(&data);
1838 srcOffset.z++;
1839 dstOffset.z++;
1840 }
Alexis Hetu33642272019-03-01 11:55:59 -05001841 }
1842 }
Alexis Hetub317d962019-04-29 14:07:31 -04001843
1844 void Blitter::computeCubeCorner(Pointer<Byte>& layer, Int& x0, Int& x1, Int& y0, Int& y1, Int& pitchB, const State& state)
1845 {
1846 int bytes = state.sourceFormat.bytes();
1847 bool quadLayout = state.sourceFormat.hasQuadLayout();
1848
1849 Float4 c0;
1850 read(c0, layer + ComputeOffset(x0, y1, pitchB, bytes, quadLayout), state);
1851 Float4 c1;
1852 read(c1, layer + ComputeOffset(x1, y0, pitchB, bytes, quadLayout), state);
1853 c0 += c1;
1854 read(c1, layer + ComputeOffset(x1, y1, pitchB, bytes, quadLayout), state);
1855 c0 += c1;
1856 c0 *= Float4(1.0f / 3.0f);
1857 write(c0, layer + ComputeOffset(x0, y0, pitchB, bytes, quadLayout), state);
1858 }
1859
Ben Clayton6897e9b2019-07-16 17:27:27 +01001860 std::shared_ptr<Routine> Blitter::generateCornerUpdate(const State& state)
Alexis Hetub317d962019-04-29 14:07:31 -04001861 {
1862 // Reading and writing from/to the same image
1863 ASSERT(state.sourceFormat == state.destFormat);
1864 ASSERT(state.srcSamples == state.destSamples);
1865
1866 if(state.srcSamples != 1)
1867 {
1868 UNIMPLEMENTED("state.srcSamples %d", state.srcSamples);
1869 }
1870
1871 Function<Void(Pointer<Byte>)> function;
1872 {
1873 Pointer<Byte> blit(function.Arg<0>());
1874
1875 Pointer<Byte> layers = *Pointer<Pointer<Byte>>(blit + OFFSET(CubeBorderData, layers));
1876 Int pitchB = *Pointer<Int>(blit + OFFSET(CubeBorderData, pitchB));
1877 UInt layerSize = *Pointer<Int>(blit + OFFSET(CubeBorderData, layerSize));
1878 UInt dim = *Pointer<Int>(blit + OFFSET(CubeBorderData, dim));
1879
1880 // Low Border, Low Pixel, High Border, High Pixel
1881 Int LB(-1), LP(0), HB(dim), HP(dim-1);
1882
Nicolas Capensbb575d42019-05-31 15:36:59 -04001883 for(int face = 0; face < 6; face++)
Alexis Hetub317d962019-04-29 14:07:31 -04001884 {
1885 computeCubeCorner(layers, LB, LP, LB, LP, pitchB, state);
1886 computeCubeCorner(layers, LB, LP, HB, HP, pitchB, state);
1887 computeCubeCorner(layers, HB, HP, LB, LP, pitchB, state);
1888 computeCubeCorner(layers, HB, HP, HB, HP, pitchB, state);
1889 layers = layers + layerSize;
1890 }
1891 }
1892
Ben Clayton056d6922019-07-04 12:41:13 +01001893 return function("BlitRoutine");
Alexis Hetub317d962019-04-29 14:07:31 -04001894 }
1895
1896 void Blitter::updateBorders(vk::Image* image, const VkImageSubresourceLayers& subresourceLayers)
1897 {
1898 if(image->getArrayLayers() < (subresourceLayers.baseArrayLayer + 6))
1899 {
1900 UNIMPLEMENTED("image->getArrayLayers() %d, baseArrayLayer %d",
1901 image->getArrayLayers(), subresourceLayers.baseArrayLayer);
1902 }
1903
1904 // From Vulkan 1.1 spec, section 11.5. Image Views:
1905 // "For cube and cube array image views, the layers of the image view starting
1906 // at baseArrayLayer correspond to faces in the order +X, -X, +Y, -Y, +Z, -Z."
1907 VkImageSubresourceLayers posX = subresourceLayers;
1908 posX.layerCount = 1;
1909 VkImageSubresourceLayers negX = posX;
1910 negX.baseArrayLayer++;
1911 VkImageSubresourceLayers posY = negX;
1912 posY.baseArrayLayer++;
1913 VkImageSubresourceLayers negY = posY;
1914 negY.baseArrayLayer++;
1915 VkImageSubresourceLayers posZ = negY;
1916 posZ.baseArrayLayer++;
1917 VkImageSubresourceLayers negZ = posZ;
1918 negZ.baseArrayLayer++;
1919
1920 // Copy top / bottom
1921 copyCubeEdge(image, posX, BOTTOM, negY, RIGHT);
1922 copyCubeEdge(image, posY, BOTTOM, posZ, TOP);
1923 copyCubeEdge(image, posZ, BOTTOM, negY, TOP);
1924 copyCubeEdge(image, negX, BOTTOM, negY, LEFT);
1925 copyCubeEdge(image, negY, BOTTOM, negZ, BOTTOM);
1926 copyCubeEdge(image, negZ, BOTTOM, negY, BOTTOM);
1927
1928 copyCubeEdge(image, posX, TOP, posY, RIGHT);
1929 copyCubeEdge(image, posY, TOP, negZ, TOP);
1930 copyCubeEdge(image, posZ, TOP, posY, BOTTOM);
1931 copyCubeEdge(image, negX, TOP, posY, LEFT);
1932 copyCubeEdge(image, negY, TOP, posZ, BOTTOM);
1933 copyCubeEdge(image, negZ, TOP, posY, TOP);
1934
1935 // Copy left / right
1936 copyCubeEdge(image, posX, RIGHT, negZ, LEFT);
1937 copyCubeEdge(image, posY, RIGHT, posX, TOP);
1938 copyCubeEdge(image, posZ, RIGHT, posX, LEFT);
1939 copyCubeEdge(image, negX, RIGHT, posZ, LEFT);
1940 copyCubeEdge(image, negY, RIGHT, posX, BOTTOM);
1941 copyCubeEdge(image, negZ, RIGHT, negX, LEFT);
1942
1943 copyCubeEdge(image, posX, LEFT, posZ, RIGHT);
1944 copyCubeEdge(image, posY, LEFT, negX, TOP);
1945 copyCubeEdge(image, posZ, LEFT, negX, RIGHT);
1946 copyCubeEdge(image, negX, LEFT, negZ, RIGHT);
1947 copyCubeEdge(image, negY, LEFT, negX, BOTTOM);
1948 copyCubeEdge(image, negZ, LEFT, posX, RIGHT);
1949
1950 // Compute corner colors
1951 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceLayers.aspectMask);
1952 vk::Format format = image->getFormat(aspect);
1953 VkSampleCountFlagBits samples = image->getSampleCountFlagBits();
1954 State state(format, format, samples, samples, { 0xF });
1955
1956 if(samples != VK_SAMPLE_COUNT_1_BIT)
1957 {
1958 UNIMPLEMENTED("Multi-sampled cube: %d samples", static_cast<int>(samples));
1959 }
1960
Ben Clayton6897e9b2019-07-16 17:27:27 +01001961 auto cornerUpdateRoutine = getCornerUpdateRoutine(state);
Alexis Hetub317d962019-04-29 14:07:31 -04001962 if(!cornerUpdateRoutine)
1963 {
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001964 return;
Alexis Hetub317d962019-04-29 14:07:31 -04001965 }
1966
Alexis Hetub317d962019-04-29 14:07:31 -04001967 void(*cornerUpdateFunction)(const CubeBorderData *data) = (void(*)(const CubeBorderData*))cornerUpdateRoutine->getEntry();
1968
Nicolas Capensba873302019-05-16 11:25:27 -04001969 VkExtent3D extent = image->getMipLevelExtent(aspect, subresourceLayers.mipLevel);
Alexis Hetub317d962019-04-29 14:07:31 -04001970 CubeBorderData data =
1971 {
1972 image->getTexelPointer({ 0, 0, 0 }, posX),
1973 image->rowPitchBytes(aspect, subresourceLayers.mipLevel),
1974 static_cast<uint32_t>(image->getLayerSize(aspect)),
1975 extent.width
1976 };
1977 cornerUpdateFunction(&data);
1978 }
1979
1980 void Blitter::copyCubeEdge(vk::Image* image,
1981 const VkImageSubresourceLayers& dstSubresourceLayers, Edge dstEdge,
1982 const VkImageSubresourceLayers& srcSubresourceLayers, Edge srcEdge)
1983 {
1984 ASSERT(srcSubresourceLayers.aspectMask == dstSubresourceLayers.aspectMask);
1985 ASSERT(srcSubresourceLayers.mipLevel == dstSubresourceLayers.mipLevel);
1986 ASSERT(srcSubresourceLayers.baseArrayLayer != dstSubresourceLayers.baseArrayLayer);
1987 ASSERT(srcSubresourceLayers.layerCount == 1);
1988 ASSERT(dstSubresourceLayers.layerCount == 1);
1989
1990 // Figure out if the edges to be copied in reverse order respectively from one another
1991 // The copy should be reversed whenever the same edges are contiguous or if we're
1992 // copying top <-> right or bottom <-> left. This is explained by the layout, which is:
1993 //
1994 // | +y |
1995 // | -x | +z | +x | -z |
1996 // | -y |
1997
1998 bool reverse = (srcEdge == dstEdge) ||
1999 ((srcEdge == TOP) && (dstEdge == RIGHT)) ||
2000 ((srcEdge == RIGHT) && (dstEdge == TOP)) ||
2001 ((srcEdge == BOTTOM) && (dstEdge == LEFT)) ||
2002 ((srcEdge == LEFT) && (dstEdge == BOTTOM));
2003
2004 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(srcSubresourceLayers.aspectMask);
2005 int bytes = image->getFormat(aspect).bytes();
2006 int pitchB = image->rowPitchBytes(aspect, srcSubresourceLayers.mipLevel);
2007
Nicolas Capensba873302019-05-16 11:25:27 -04002008 VkExtent3D extent = image->getMipLevelExtent(aspect, srcSubresourceLayers.mipLevel);
Alexis Hetub317d962019-04-29 14:07:31 -04002009 int w = extent.width;
2010 int h = extent.height;
2011 if(w != h)
2012 {
2013 UNIMPLEMENTED("Cube doesn't have square faces : (%d, %d)", w, h);
2014 }
2015
2016 // Src is expressed in the regular [0, width-1], [0, height-1] space
2017 bool srcHorizontal = ((srcEdge == TOP) || (srcEdge == BOTTOM));
2018 int srcDelta = srcHorizontal ? bytes : pitchB;
2019 VkOffset3D srcOffset = { (srcEdge == RIGHT) ? (w - 1) : 0, (srcEdge == BOTTOM) ? (h - 1) : 0, 0 };
2020
2021 // Dst contains borders, so it is expressed in the [-1, width], [-1, height] space
2022 bool dstHorizontal = ((dstEdge == TOP) || (dstEdge == BOTTOM));
2023 int dstDelta = (dstHorizontal ? bytes : pitchB) * (reverse ? -1 : 1);
2024 VkOffset3D dstOffset = { (dstEdge == RIGHT) ? w : -1, (dstEdge == BOTTOM) ? h : -1, 0 };
2025
2026 // Don't write in the corners
2027 if(dstHorizontal)
2028 {
2029 dstOffset.x += reverse ? w : 1;
2030 }
2031 else
2032 {
2033 dstOffset.y += reverse ? h : 1;
2034 }
2035
2036 const uint8_t* src = static_cast<const uint8_t*>(image->getTexelPointer(srcOffset, srcSubresourceLayers));
2037 uint8_t *dst = static_cast<uint8_t*>(image->getTexelPointer(dstOffset, dstSubresourceLayers));
2038 ASSERT((src < image->end()) && ((src + (w * srcDelta)) < image->end()));
2039 ASSERT((dst < image->end()) && ((dst + (w * dstDelta)) < image->end()));
2040
2041 for(int i = 0; i < w; ++i, dst += dstDelta, src += srcDelta)
2042 {
2043 memcpy(dst, src, bytes);
2044 }
2045 }
Nicolas Capens68a82382018-10-02 13:16:55 -04002046}