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