blob: abd5a9126e7954fbbae2c823fc2461b9209db5af [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 Capensa2e6c1a2020-08-26 15:44:50 -040019#include "System/CPUID.hpp"
Ben Clayton25e06e02020-02-07 11:19:08 +000020#include "System/Debug.hpp"
Nicolas Capens02cbe8e2019-08-05 15:10:05 -040021#include "System/Half.hpp"
Nicolas Capens1d8c8db2018-11-05 16:30:42 -050022#include "System/Memory.hpp"
Ben Claytonfccfc562019-12-17 20:37:31 +000023#include "Vulkan/VkBuffer.hpp"
Alexis Hetu33642272019-03-01 11:55:59 -050024#include "Vulkan/VkImage.hpp"
Sean Risser1d5174b2020-09-22 16:58:28 -040025#include "Vulkan/VkImageView.hpp"
Nicolas Capens68a82382018-10-02 13:16:55 -040026
Nicolas Capensb8c63932019-03-19 01:52:40 -040027#include <utility>
28
Nicolas Capensa2e6c1a2020-08-26 15:44:50 -040029#if defined(__i386__) || defined(__x86_64__)
30# include <xmmintrin.h>
31# include <emmintrin.h>
32#endif
33
Alexis Hetu3716c202019-12-19 17:09:08 -050034namespace {
35rr::RValue<rr::Int> PackFields(rr::Int4 const &ints, const sw::int4 shifts)
36{
37 return (rr::Int(ints.x) << shifts[0]) |
38 (rr::Int(ints.y) << shifts[1]) |
39 (rr::Int(ints.z) << shifts[2]) |
40 (rr::Int(ints.w) << shifts[3]);
41}
42} // namespace
43
Nicolas Capens157ba262019-12-10 17:49:14 -050044namespace sw {
45
Ben Claytonfccfc562019-12-17 20:37:31 +000046Blitter::Blitter()
47 : blitMutex()
48 , blitCache(1024)
49 , cornerUpdateMutex()
50 , cornerUpdateCache(64) // We only need one of these per format
Nicolas Capens68a82382018-10-02 13:16:55 -040051{
Nicolas Capens157ba262019-12-10 17:49:14 -050052}
53
54Blitter::~Blitter()
55{
56}
57
Ben Claytonfccfc562019-12-17 20:37:31 +000058void Blitter::clear(void *pixel, vk::Format format, vk::Image *dest, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea)
Nicolas Capens157ba262019-12-10 17:49:14 -050059{
60 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask);
61 vk::Format dstFormat = viewFormat.getAspectFormat(aspect);
62 if(dstFormat == VK_FORMAT_UNDEFINED)
Nicolas Capens68a82382018-10-02 13:16:55 -040063 {
Nicolas Capens157ba262019-12-10 17:49:14 -050064 return;
Nicolas Capens68a82382018-10-02 13:16:55 -040065 }
66
Nicolas Capens157ba262019-12-10 17:49:14 -050067 float *pPixel = static_cast<float *>(pixel);
Alexis Hetu64da65b2020-05-12 16:38:35 -040068 if(viewFormat.isUnsignedNormalized() || viewFormat.isSRGBformat())
Nicolas Capens68a82382018-10-02 13:16:55 -040069 {
Nicolas Capens157ba262019-12-10 17:49:14 -050070 pPixel[0] = sw::clamp(pPixel[0], 0.0f, 1.0f);
71 pPixel[1] = sw::clamp(pPixel[1], 0.0f, 1.0f);
72 pPixel[2] = sw::clamp(pPixel[2], 0.0f, 1.0f);
73 pPixel[3] = sw::clamp(pPixel[3], 0.0f, 1.0f);
74 }
Nicolas Capens81bc9d92019-12-16 15:05:57 -050075 else if(viewFormat.isSignedNormalized())
Nicolas Capens157ba262019-12-10 17:49:14 -050076 {
77 pPixel[0] = sw::clamp(pPixel[0], -1.0f, 1.0f);
78 pPixel[1] = sw::clamp(pPixel[1], -1.0f, 1.0f);
79 pPixel[2] = sw::clamp(pPixel[2], -1.0f, 1.0f);
80 pPixel[3] = sw::clamp(pPixel[3], -1.0f, 1.0f);
Nicolas Capens68a82382018-10-02 13:16:55 -040081 }
82
Nicolas Capens157ba262019-12-10 17:49:14 -050083 if(fastClear(pixel, format, dest, dstFormat, subresourceRange, renderArea))
Alexis Hetu33642272019-03-01 11:55:59 -050084 {
Nicolas Capens157ba262019-12-10 17:49:14 -050085 return;
86 }
87
88 State state(format, dstFormat, 1, dest->getSampleCountFlagBits(), Options{ 0xF });
89 auto blitRoutine = getBlitRoutine(state);
90 if(!blitRoutine)
91 {
92 return;
93 }
94
Alexis Hetu46159712020-06-15 16:13:51 -040095 VkImageSubresource subres = {
Nicolas Capens157ba262019-12-10 17:49:14 -050096 subresourceRange.aspectMask,
97 subresourceRange.baseMipLevel,
Alexis Hetu46159712020-06-15 16:13:51 -040098 subresourceRange.baseArrayLayer
Nicolas Capens157ba262019-12-10 17:49:14 -050099 };
100
101 uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange);
102 uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange);
103
104 VkRect2D area = { { 0, 0 }, { 0, 0 } };
105 if(renderArea)
106 {
107 ASSERT(subresourceRange.levelCount == 1);
108 area = *renderArea;
109 }
110
Alexis Hetu46159712020-06-15 16:13:51 -0400111 for(; subres.mipLevel <= lastMipLevel; subres.mipLevel++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500112 {
Alexis Hetu46159712020-06-15 16:13:51 -0400113 VkExtent3D extent = dest->getMipLevelExtent(aspect, subres.mipLevel);
Nicolas Capens157ba262019-12-10 17:49:14 -0500114 if(!renderArea)
Alexis Hetu33642272019-03-01 11:55:59 -0500115 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500116 area.extent.width = extent.width;
117 area.extent.height = extent.height;
Alexis Hetu33642272019-03-01 11:55:59 -0500118 }
119
Ben Claytonfccfc562019-12-17 20:37:31 +0000120 BlitData data = {
121 pixel, nullptr, // source, dest
Chris Forbes88289192019-08-28 16:49:36 -0700122
Alexis Hetu46159712020-06-15 16:13:51 -0400123 format.bytes(), // sPitchB
124 dest->rowPitchBytes(aspect, subres.mipLevel), // dPitchB
125 0, // sSliceB (unused in clear operations)
126 dest->slicePitchBytes(aspect, subres.mipLevel), // dSliceB
Alexis Hetu33642272019-03-01 11:55:59 -0500127
Alexis Hetu18daa812020-03-11 17:06:53 -0400128 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, // x0, y0, z0, w, h, d
Alexis Hetu33642272019-03-01 11:55:59 -0500129
Ben Claytonfccfc562019-12-17 20:37:31 +0000130 area.offset.x, static_cast<int>(area.offset.x + area.extent.width), // x0d, x1d
Alexis Hetu18daa812020-03-11 17:06:53 -0400131 area.offset.y, static_cast<int>(area.offset.y + area.extent.height), // y0d, y1d
132 0, 1, // z0d, z1d
Nicolas Capens157ba262019-12-10 17:49:14 -0500133
Alexis Hetu18daa812020-03-11 17:06:53 -0400134 0, 0, 0, // sWidth, sHeight, sDepth
Ben Clayton21fb75f2020-04-16 10:36:55 +0100135
136 false, // filter3D
Alexis Hetu33642272019-03-01 11:55:59 -0500137 };
138
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500139 if(renderArea && dest->is3DSlice())
Alexis Hetu33642272019-03-01 11:55:59 -0500140 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500141 // Reinterpret layers as depth slices
Alexis Hetu46159712020-06-15 16:13:51 -0400142 subres.arrayLayer = 0;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500143 for(uint32_t depth = subresourceRange.baseArrayLayer; depth <= lastLayer; depth++)
Alexis Hetu33642272019-03-01 11:55:59 -0500144 {
Alexis Hetu46159712020-06-15 16:13:51 -0400145 data.dest = dest->getTexelPointer({ 0, 0, static_cast<int32_t>(depth) }, subres);
Nicolas Capens157ba262019-12-10 17:49:14 -0500146 blitRoutine(&data);
Nicolas Capens68a82382018-10-02 13:16:55 -0400147 }
148 }
Nicolas Capens88ac3672019-08-01 13:22:34 -0400149 else
Nicolas Capens68a82382018-10-02 13:16:55 -0400150 {
Alexis Hetu46159712020-06-15 16:13:51 -0400151 for(subres.arrayLayer = subresourceRange.baseArrayLayer; subres.arrayLayer <= lastLayer; subres.arrayLayer++)
Nicolas Capens68a82382018-10-02 13:16:55 -0400152 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500153 for(uint32_t depth = 0; depth < extent.depth; depth++)
Nicolas Capens68a82382018-10-02 13:16:55 -0400154 {
Alexis Hetu46159712020-06-15 16:13:51 -0400155 data.dest = dest->getTexelPointer({ 0, 0, static_cast<int32_t>(depth) }, subres);
Nicolas Capens157ba262019-12-10 17:49:14 -0500156
157 blitRoutine(&data);
158 }
159 }
160 }
161 }
Alexis Hetu4f438a52020-06-15 16:13:51 -0400162 dest->contentsChanged(subresourceRange);
Nicolas Capens157ba262019-12-10 17:49:14 -0500163}
164
Nicolas Capensb3240d02020-06-10 22:40:19 -0400165bool Blitter::fastClear(void *clearValue, vk::Format clearFormat, vk::Image *dest, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea)
Nicolas Capens157ba262019-12-10 17:49:14 -0500166{
Nicolas Capensb3240d02020-06-10 22:40:19 -0400167 if(clearFormat != VK_FORMAT_R32G32B32A32_SFLOAT &&
168 clearFormat != VK_FORMAT_D32_SFLOAT &&
169 clearFormat != VK_FORMAT_S8_UINT)
Nicolas Capens157ba262019-12-10 17:49:14 -0500170 {
171 return false;
172 }
173
Nicolas Capensb3240d02020-06-10 22:40:19 -0400174 union ClearValue
175 {
176 struct
177 {
178 float r;
179 float g;
180 float b;
181 float a;
182 };
Nicolas Capens157ba262019-12-10 17:49:14 -0500183
Nicolas Capensb3240d02020-06-10 22:40:19 -0400184 float rgb[3];
185
186 float d;
187 uint32_t d_as_u32;
188
189 uint32_t s;
190 };
191
192 ClearValue &c = *reinterpret_cast<ClearValue *>(clearValue);
193
194 uint32_t packed = 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500195
196 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask);
197 switch(viewFormat)
198 {
Ben Claytonfccfc562019-12-17 20:37:31 +0000199 case VK_FORMAT_R5G6B5_UNORM_PACK16:
Nicolas Capensb3240d02020-06-10 22:40:19 -0400200 packed = ((uint16_t)(31 * c.b + 0.5f) << 0) |
201 ((uint16_t)(63 * c.g + 0.5f) << 5) |
202 ((uint16_t)(31 * c.r + 0.5f) << 11);
Ben Claytonfccfc562019-12-17 20:37:31 +0000203 break;
204 case VK_FORMAT_B5G6R5_UNORM_PACK16:
Nicolas Capensb3240d02020-06-10 22:40:19 -0400205 packed = ((uint16_t)(31 * c.r + 0.5f) << 0) |
206 ((uint16_t)(63 * c.g + 0.5f) << 5) |
207 ((uint16_t)(31 * c.b + 0.5f) << 11);
Ben Claytonfccfc562019-12-17 20:37:31 +0000208 break;
209 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
210 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
211 case VK_FORMAT_R8G8B8A8_UNORM:
Nicolas Capensb3240d02020-06-10 22:40:19 -0400212 packed = ((uint32_t)(255 * c.a + 0.5f) << 24) |
213 ((uint32_t)(255 * c.b + 0.5f) << 16) |
214 ((uint32_t)(255 * c.g + 0.5f) << 8) |
215 ((uint32_t)(255 * c.r + 0.5f) << 0);
Ben Claytonfccfc562019-12-17 20:37:31 +0000216 break;
217 case VK_FORMAT_B8G8R8A8_UNORM:
Nicolas Capensb3240d02020-06-10 22:40:19 -0400218 packed = ((uint32_t)(255 * c.a + 0.5f) << 24) |
219 ((uint32_t)(255 * c.r + 0.5f) << 16) |
220 ((uint32_t)(255 * c.g + 0.5f) << 8) |
221 ((uint32_t)(255 * c.b + 0.5f) << 0);
Ben Claytonfccfc562019-12-17 20:37:31 +0000222 break;
223 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
Nicolas Capensb3240d02020-06-10 22:40:19 -0400224 packed = R11G11B10F(c.rgb);
Ben Claytonfccfc562019-12-17 20:37:31 +0000225 break;
226 case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
Nicolas Capensb3240d02020-06-10 22:40:19 -0400227 packed = RGB9E5(c.rgb);
228 break;
229 case VK_FORMAT_D32_SFLOAT:
230 ASSERT(clearFormat == VK_FORMAT_D32_SFLOAT);
231 packed = c.d_as_u32; // float reinterpreted as uint32
232 break;
233 case VK_FORMAT_S8_UINT:
234 ASSERT(clearFormat == VK_FORMAT_S8_UINT);
235 packed = static_cast<uint8_t>(c.s);
Ben Claytonfccfc562019-12-17 20:37:31 +0000236 break;
237 default:
238 return false;
Nicolas Capens157ba262019-12-10 17:49:14 -0500239 }
240
Alexis Hetu46159712020-06-15 16:13:51 -0400241 VkImageSubresource subres = {
Nicolas Capens157ba262019-12-10 17:49:14 -0500242 subresourceRange.aspectMask,
243 subresourceRange.baseMipLevel,
Alexis Hetu46159712020-06-15 16:13:51 -0400244 subresourceRange.baseArrayLayer
Nicolas Capens157ba262019-12-10 17:49:14 -0500245 };
246 uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange);
247 uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange);
248
249 VkRect2D area = { { 0, 0 }, { 0, 0 } };
250 if(renderArea)
251 {
252 ASSERT(subresourceRange.levelCount == 1);
253 area = *renderArea;
254 }
255
Alexis Hetu46159712020-06-15 16:13:51 -0400256 for(; subres.mipLevel <= lastMipLevel; subres.mipLevel++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500257 {
Alexis Hetu46159712020-06-15 16:13:51 -0400258 int rowPitchBytes = dest->rowPitchBytes(aspect, subres.mipLevel);
259 int slicePitchBytes = dest->slicePitchBytes(aspect, subres.mipLevel);
260 VkExtent3D extent = dest->getMipLevelExtent(aspect, subres.mipLevel);
Nicolas Capens157ba262019-12-10 17:49:14 -0500261 if(!renderArea)
262 {
263 area.extent.width = extent.width;
264 area.extent.height = extent.height;
265 }
266 if(dest->is3DSlice())
267 {
Ben Claytonfccfc562019-12-17 20:37:31 +0000268 extent.depth = 1; // The 3D image is instead interpreted as a 2D image with layers
Nicolas Capens157ba262019-12-10 17:49:14 -0500269 }
270
Alexis Hetu46159712020-06-15 16:13:51 -0400271 for(subres.arrayLayer = subresourceRange.baseArrayLayer; subres.arrayLayer <= lastLayer; subres.arrayLayer++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500272 {
273 for(uint32_t depth = 0; depth < extent.depth; depth++)
274 {
Ben Claytonfccfc562019-12-17 20:37:31 +0000275 uint8_t *slice = (uint8_t *)dest->getTexelPointer(
Alexis Hetu46159712020-06-15 16:13:51 -0400276 { area.offset.x, area.offset.y, static_cast<int32_t>(depth) }, subres);
Nicolas Capens157ba262019-12-10 17:49:14 -0500277
278 for(int j = 0; j < dest->getSampleCountFlagBits(); j++)
279 {
280 uint8_t *d = slice;
281
282 switch(viewFormat.bytes())
283 {
Nicolas Capensb3240d02020-06-10 22:40:19 -0400284 case 4:
285 for(uint32_t i = 0; i < area.extent.height; i++)
286 {
287 ASSERT(d < dest->end());
288 sw::clear((uint32_t *)d, packed, area.extent.width);
289 d += rowPitchBytes;
290 }
291 break;
Ben Claytonfccfc562019-12-17 20:37:31 +0000292 case 2:
293 for(uint32_t i = 0; i < area.extent.height; i++)
294 {
295 ASSERT(d < dest->end());
296 sw::clear((uint16_t *)d, static_cast<uint16_t>(packed), area.extent.width);
297 d += rowPitchBytes;
298 }
299 break;
Nicolas Capensb3240d02020-06-10 22:40:19 -0400300 case 1:
Ben Claytonfccfc562019-12-17 20:37:31 +0000301 for(uint32_t i = 0; i < area.extent.height; i++)
302 {
303 ASSERT(d < dest->end());
Nicolas Capensb3240d02020-06-10 22:40:19 -0400304 memset(d, packed, area.extent.width);
Ben Claytonfccfc562019-12-17 20:37:31 +0000305 d += rowPitchBytes;
306 }
307 break;
308 default:
309 assert(false);
Nicolas Capens157ba262019-12-10 17:49:14 -0500310 }
311
312 slice += slicePitchBytes;
313 }
314 }
315 }
316 }
Alexis Hetu4f438a52020-06-15 16:13:51 -0400317 dest->contentsChanged(subresourceRange);
Nicolas Capens157ba262019-12-10 17:49:14 -0500318
319 return true;
320}
321
322Float4 Blitter::readFloat4(Pointer<Byte> element, const State &state)
323{
324 Float4 c(0.0f, 0.0f, 0.0f, 1.0f);
325
326 switch(state.sourceFormat)
327 {
Ben Claytonfccfc562019-12-17 20:37:31 +0000328 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
329 c.w = Float(Int(*Pointer<Byte>(element)) & Int(0xF));
330 c.x = Float((Int(*Pointer<Byte>(element)) >> 4) & Int(0xF));
331 c.y = Float(Int(*Pointer<Byte>(element + 1)) & Int(0xF));
332 c.z = Float((Int(*Pointer<Byte>(element + 1)) >> 4) & Int(0xF));
333 break;
334 case VK_FORMAT_R8_SINT:
335 case VK_FORMAT_R8_SNORM:
336 c.x = Float(Int(*Pointer<SByte>(element)));
337 c.w = float(0x7F);
338 break;
339 case VK_FORMAT_R8_UNORM:
340 case VK_FORMAT_R8_UINT:
341 case VK_FORMAT_R8_SRGB:
342 c.x = Float(Int(*Pointer<Byte>(element)));
343 c.w = float(0xFF);
344 break;
345 case VK_FORMAT_R16_SINT:
346 case VK_FORMAT_R16_SNORM:
347 c.x = Float(Int(*Pointer<Short>(element)));
348 c.w = float(0x7FFF);
349 break;
350 case VK_FORMAT_R16_UNORM:
351 case VK_FORMAT_R16_UINT:
352 c.x = Float(Int(*Pointer<UShort>(element)));
353 c.w = float(0xFFFF);
354 break;
355 case VK_FORMAT_R32_SINT:
356 c.x = Float(*Pointer<Int>(element));
357 c.w = float(0x7FFFFFFF);
358 break;
359 case VK_FORMAT_R32_UINT:
360 c.x = Float(*Pointer<UInt>(element));
361 c.w = float(0xFFFFFFFF);
362 break;
363 case VK_FORMAT_B8G8R8A8_SRGB:
364 case VK_FORMAT_B8G8R8A8_UNORM:
365 c = Float4(*Pointer<Byte4>(element)).zyxw;
366 break;
367 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
368 case VK_FORMAT_R8G8B8A8_SINT:
369 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
370 case VK_FORMAT_R8G8B8A8_SNORM:
371 c = Float4(*Pointer<SByte4>(element));
372 break;
373 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
374 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
375 case VK_FORMAT_R8G8B8A8_UNORM:
376 case VK_FORMAT_R8G8B8A8_UINT:
377 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
378 case VK_FORMAT_R8G8B8A8_SRGB:
379 c = Float4(*Pointer<Byte4>(element));
380 break;
381 case VK_FORMAT_R16G16B16A16_SINT:
Nicolas Capensf6f11212020-07-01 00:27:23 -0400382 case VK_FORMAT_R16G16B16A16_SNORM:
Ben Claytonfccfc562019-12-17 20:37:31 +0000383 c = Float4(*Pointer<Short4>(element));
384 break;
385 case VK_FORMAT_R16G16B16A16_UNORM:
386 case VK_FORMAT_R16G16B16A16_UINT:
387 c = Float4(*Pointer<UShort4>(element));
388 break;
389 case VK_FORMAT_R32G32B32A32_SINT:
390 c = Float4(*Pointer<Int4>(element));
391 break;
392 case VK_FORMAT_R32G32B32A32_UINT:
393 c = Float4(*Pointer<UInt4>(element));
394 break;
395 case VK_FORMAT_R8G8_SINT:
396 case VK_FORMAT_R8G8_SNORM:
397 c.x = Float(Int(*Pointer<SByte>(element + 0)));
398 c.y = Float(Int(*Pointer<SByte>(element + 1)));
399 c.w = float(0x7F);
400 break;
401 case VK_FORMAT_R8G8_UNORM:
402 case VK_FORMAT_R8G8_UINT:
403 case VK_FORMAT_R8G8_SRGB:
404 c.x = Float(Int(*Pointer<Byte>(element + 0)));
405 c.y = Float(Int(*Pointer<Byte>(element + 1)));
406 c.w = float(0xFF);
407 break;
408 case VK_FORMAT_R16G16_SINT:
409 case VK_FORMAT_R16G16_SNORM:
410 c.x = Float(Int(*Pointer<Short>(element + 0)));
411 c.y = Float(Int(*Pointer<Short>(element + 2)));
412 c.w = float(0x7FFF);
413 break;
414 case VK_FORMAT_R16G16_UNORM:
415 case VK_FORMAT_R16G16_UINT:
416 c.x = Float(Int(*Pointer<UShort>(element + 0)));
417 c.y = Float(Int(*Pointer<UShort>(element + 2)));
418 c.w = float(0xFFFF);
419 break;
420 case VK_FORMAT_R32G32_SINT:
421 c.x = Float(*Pointer<Int>(element + 0));
422 c.y = Float(*Pointer<Int>(element + 4));
423 c.w = float(0x7FFFFFFF);
424 break;
425 case VK_FORMAT_R32G32_UINT:
426 c.x = Float(*Pointer<UInt>(element + 0));
427 c.y = Float(*Pointer<UInt>(element + 4));
428 c.w = float(0xFFFFFFFF);
429 break;
430 case VK_FORMAT_R32G32B32A32_SFLOAT:
431 c = *Pointer<Float4>(element);
432 break;
433 case VK_FORMAT_R32G32_SFLOAT:
434 c.x = *Pointer<Float>(element + 0);
435 c.y = *Pointer<Float>(element + 4);
436 break;
437 case VK_FORMAT_R32_SFLOAT:
438 c.x = *Pointer<Float>(element);
439 break;
440 case VK_FORMAT_R16G16B16A16_SFLOAT:
441 c.w = Float(*Pointer<Half>(element + 6));
442 case VK_FORMAT_R16G16B16_SFLOAT:
443 c.z = Float(*Pointer<Half>(element + 4));
444 case VK_FORMAT_R16G16_SFLOAT:
445 c.y = Float(*Pointer<Half>(element + 2));
446 case VK_FORMAT_R16_SFLOAT:
447 c.x = Float(*Pointer<Half>(element));
448 break;
449 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
450 c = r11g11b10Unpack(*Pointer<UInt>(element));
451 break;
452 case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
453 // This type contains a common 5 bit exponent (E) and a 9 bit the mantissa for R, G and B.
454 c.x = Float(*Pointer<UInt>(element) & UInt(0x000001FF)); // R's mantissa (bits 0-8)
455 c.y = Float((*Pointer<UInt>(element) & UInt(0x0003FE00)) >> 9); // G's mantissa (bits 9-17)
456 c.z = Float((*Pointer<UInt>(element) & UInt(0x07FC0000)) >> 18); // B's mantissa (bits 18-26)
457 c *= Float4(
458 // 2^E, using the exponent (bits 27-31) and treating it as an unsigned integer value
459 Float(UInt(1) << ((*Pointer<UInt>(element) & UInt(0xF8000000)) >> 27)) *
460 // Since the 9 bit mantissa values currently stored in RGB were converted straight
461 // from int to float (in the [0, 1<<9] range instead of the [0, 1] range), they
462 // are (1 << 9) times too high.
463 // Also, the exponent has 5 bits and we compute the exponent bias of floating point
464 // formats using "2^(k-1) - 1", so, in this case, the exponent bias is 2^(5-1)-1 = 15
465 // Exponent bias (15) + number of mantissa bits per component (9) = 24
466 Float(1.0f / (1 << 24)));
467 c.w = 1.0f;
468 break;
469 case VK_FORMAT_R5G6B5_UNORM_PACK16:
470 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
471 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07E0)) >> UShort(5)));
472 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
473 break;
474 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
475 c.w = Float(Int((*Pointer<UShort>(element) & UShort(0x8000)) >> UShort(15)));
476 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0x7C00)) >> UShort(10)));
477 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x03E0)) >> UShort(5)));
478 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
479 break;
480 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
481 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
482 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
483 c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
484 c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
485 c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
486 break;
Alexis Hetub8a61bf2020-01-09 15:26:34 -0500487 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
488 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
489 c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
490 c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
491 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
492 c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
493 break;
Ben Claytonfccfc562019-12-17 20:37:31 +0000494 case VK_FORMAT_D16_UNORM:
495 c.x = Float(Int((*Pointer<UShort>(element))));
496 break;
497 case VK_FORMAT_X8_D24_UNORM_PACK32:
498 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0xFFFFFF00)) >> 8));
499 break;
500 case VK_FORMAT_D32_SFLOAT:
501 c.x = *Pointer<Float>(element);
502 break;
503 case VK_FORMAT_S8_UINT:
504 c.x = Float(Int(*Pointer<Byte>(element)));
505 break;
506 default:
507 UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
Nicolas Capens157ba262019-12-10 17:49:14 -0500508 }
509
510 return c;
511}
512
513void Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
514{
515 bool writeR = state.writeRed;
516 bool writeG = state.writeGreen;
517 bool writeB = state.writeBlue;
518 bool writeA = state.writeAlpha;
519 bool writeRGBA = writeR && writeG && writeB && writeA;
520
521 switch(state.destFormat)
522 {
Ben Claytonfccfc562019-12-17 20:37:31 +0000523 case VK_FORMAT_R4G4_UNORM_PACK8:
524 if(writeR | writeG)
Nicolas Capens157ba262019-12-10 17:49:14 -0500525 {
Ben Claytonfccfc562019-12-17 20:37:31 +0000526 if(!writeR)
527 {
528 *Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
529 (*Pointer<Byte>(element) & Byte(0xF0));
530 }
531 else if(!writeG)
532 {
533 *Pointer<Byte>(element) = (*Pointer<Byte>(element) & Byte(0xF)) |
534 (Byte(RoundInt(Float(c.x))) << Byte(4));
535 }
536 else
537 {
538 *Pointer<Byte>(element) = (Byte(RoundInt(Float(c.y))) & Byte(0xF)) |
539 (Byte(RoundInt(Float(c.x))) << Byte(4));
540 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500541 }
Ben Claytonfccfc562019-12-17 20:37:31 +0000542 break;
543 case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
544 if(writeR || writeG || writeB || writeA)
Nicolas Capens157ba262019-12-10 17:49:14 -0500545 {
Ben Claytonfccfc562019-12-17 20:37:31 +0000546 *Pointer<UShort>(element) = (writeR ? ((UShort(RoundInt(Float(c.x))) & UShort(0xF)) << UShort(12)) : (*Pointer<UShort>(element) & UShort(0x000F))) |
547 (writeG ? ((UShort(RoundInt(Float(c.y))) & UShort(0xF)) << UShort(8)) : (*Pointer<UShort>(element) & UShort(0x00F0))) |
548 (writeB ? ((UShort(RoundInt(Float(c.z))) & UShort(0xF)) << UShort(4)) : (*Pointer<UShort>(element) & UShort(0x0F00))) |
549 (writeA ? (UShort(RoundInt(Float(c.w))) & UShort(0xF)) : (*Pointer<UShort>(element) & UShort(0xF000)));
550 }
551 break;
552 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
553 if(writeRGBA)
554 {
555 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.w)) & Int(0xF)) |
556 UShort((RoundInt(Float(c.x)) & Int(0xF)) << 4) |
557 UShort((RoundInt(Float(c.y)) & Int(0xF)) << 8) |
558 UShort((RoundInt(Float(c.z)) & Int(0xF)) << 12);
Nicolas Capens157ba262019-12-10 17:49:14 -0500559 }
560 else
561 {
Ben Claytonfccfc562019-12-17 20:37:31 +0000562 unsigned short mask = (writeA ? 0x000F : 0x0000) |
563 (writeR ? 0x00F0 : 0x0000) |
564 (writeG ? 0x0F00 : 0x0000) |
565 (writeB ? 0xF000 : 0x0000);
566 unsigned short unmask = ~mask;
567 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
568 ((UShort(RoundInt(Float(c.w)) & Int(0xF)) |
569 UShort((RoundInt(Float(c.x)) & Int(0xF)) << 4) |
570 UShort((RoundInt(Float(c.y)) & Int(0xF)) << 8) |
571 UShort((RoundInt(Float(c.z)) & Int(0xF)) << 12)) &
572 UShort(mask));
Nicolas Capens157ba262019-12-10 17:49:14 -0500573 }
Ben Claytonfccfc562019-12-17 20:37:31 +0000574 break;
575 case VK_FORMAT_B8G8R8A8_SRGB:
576 case VK_FORMAT_B8G8R8A8_UNORM:
577 if(writeRGBA)
578 {
579 Short4 c0 = RoundShort4(c.zyxw);
580 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
581 }
582 else
583 {
584 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
585 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
586 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
587 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
588 }
589 break;
590 case VK_FORMAT_B8G8R8_SNORM:
591 if(writeB) { *Pointer<SByte>(element + 0) = SByte(RoundInt(Float(c.z))); }
592 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
593 if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
594 break;
595 case VK_FORMAT_B8G8R8_UNORM:
596 case VK_FORMAT_B8G8R8_SRGB:
Nicolas Capens157ba262019-12-10 17:49:14 -0500597 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
598 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
599 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
Ben Claytonfccfc562019-12-17 20:37:31 +0000600 break;
601 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
602 case VK_FORMAT_R8G8B8A8_UNORM:
603 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
604 case VK_FORMAT_R8G8B8A8_SRGB:
605 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
606 case VK_FORMAT_R8G8B8A8_UINT:
607 case VK_FORMAT_R8G8B8A8_USCALED:
608 case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
609 if(writeRGBA)
610 {
611 Short4 c0 = RoundShort4(c);
612 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
613 }
614 else
615 {
616 if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
617 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
618 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
619 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
620 }
621 break;
622 case VK_FORMAT_R32G32B32A32_SFLOAT:
623 if(writeRGBA)
624 {
625 *Pointer<Float4>(element) = c;
626 }
627 else
628 {
629 if(writeR) { *Pointer<Float>(element) = c.x; }
630 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
631 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
632 if(writeA) { *Pointer<Float>(element + 12) = c.w; }
633 }
634 break;
635 case VK_FORMAT_R32G32B32_SFLOAT:
Nicolas Capens157ba262019-12-10 17:49:14 -0500636 if(writeR) { *Pointer<Float>(element) = c.x; }
637 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
638 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
Ben Claytonfccfc562019-12-17 20:37:31 +0000639 break;
640 case VK_FORMAT_R32G32_SFLOAT:
641 if(writeR && writeG)
642 {
643 *Pointer<Float2>(element) = Float2(c);
644 }
645 else
646 {
647 if(writeR) { *Pointer<Float>(element) = c.x; }
648 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
649 }
650 break;
651 case VK_FORMAT_R32_SFLOAT:
Nicolas Capens157ba262019-12-10 17:49:14 -0500652 if(writeR) { *Pointer<Float>(element) = c.x; }
Ben Claytonfccfc562019-12-17 20:37:31 +0000653 break;
654 case VK_FORMAT_R16G16B16A16_SFLOAT:
655 if(writeA) { *Pointer<Half>(element + 6) = Half(c.w); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500656 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000657 case VK_FORMAT_R16G16B16_SFLOAT:
658 if(writeB) { *Pointer<Half>(element + 4) = Half(c.z); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500659 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000660 case VK_FORMAT_R16G16_SFLOAT:
661 if(writeG) { *Pointer<Half>(element + 2) = Half(c.y); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500662 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000663 case VK_FORMAT_R16_SFLOAT:
664 if(writeR) { *Pointer<Half>(element) = Half(c.x); }
665 break;
666 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
Nicolas Capens157ba262019-12-10 17:49:14 -0500667 {
Alexis Hetu24c49dd2019-12-13 16:32:43 -0500668 UInt rgb = r11g11b10Pack(c);
Nicolas Capens157ba262019-12-10 17:49:14 -0500669
670 UInt old = *Pointer<UInt>(element);
671
672 unsigned int mask = (writeR ? 0x000007FF : 0) |
673 (writeG ? 0x003FF800 : 0) |
674 (writeB ? 0xFFC00000 : 0);
675
676 *Pointer<UInt>(element) = (rgb & mask) | (old & ~mask);
677 }
678 break;
Ben Claytonfccfc562019-12-17 20:37:31 +0000679 case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
Nicolas Capens157ba262019-12-10 17:49:14 -0500680 {
681 ASSERT(writeRGBA); // Can't sensibly write just part of this format.
682
683 // Vulkan 1.1.117 section 15.2.1 RGB to Shared Exponent Conversion
684
685 constexpr int N = 9; // number of mantissa bits per component
686 constexpr int B = 15; // exponent bias
687 constexpr int E_max = 31; // maximum possible biased exponent value
688
689 // Maximum representable value.
690 constexpr float sharedexp_max = ((static_cast<float>(1 << N) - 1) / static_cast<float>(1 << N)) * static_cast<float>(1 << (E_max - B));
691
692 // Clamp components to valid range. NaN becomes 0.
Ben Claytonfccfc562019-12-17 20:37:31 +0000693 Float red_c = Min(IfThenElse(!(c.x > 0), Float(0), Float(c.x)), sharedexp_max);
Nicolas Capens157ba262019-12-10 17:49:14 -0500694 Float green_c = Min(IfThenElse(!(c.y > 0), Float(0), Float(c.y)), sharedexp_max);
Ben Claytonfccfc562019-12-17 20:37:31 +0000695 Float blue_c = Min(IfThenElse(!(c.z > 0), Float(0), Float(c.z)), sharedexp_max);
Nicolas Capens157ba262019-12-10 17:49:14 -0500696
697 // We're reducing the mantissa to 9 bits, so we must round up if the next
698 // bit is 1. In other words add 0.5 to the new mantissa's position and
699 // allow overflow into the exponent so we can scale correctly.
700 constexpr int half = 1 << (23 - N);
701 Float red_r = As<Float>(As<Int>(red_c) + half);
702 Float green_r = As<Float>(As<Int>(green_c) + half);
703 Float blue_r = As<Float>(As<Int>(blue_c) + half);
704
705 // The largest component determines the shared exponent. It can't be lower
706 // than 0 (after bias subtraction) so also limit to the mimimum representable.
707 constexpr float min_s = 0.5f / (1 << B);
708 Float max_s = Max(Max(red_r, green_r), Max(blue_r, min_s));
709
710 // Obtain the reciprocal of the shared exponent by inverting the bits,
711 // and scale by the new mantissa's size. Note that the IEEE-754 single-precision
712 // format has an implicit leading 1, but this shared component format does not.
713 Float scale = As<Float>((As<Int>(max_s) & 0x7F800000) ^ 0x7F800000) * (1 << (N - 2));
714
715 UInt R9 = RoundInt(red_c * scale);
716 UInt G9 = UInt(RoundInt(green_c * scale));
717 UInt B9 = UInt(RoundInt(blue_c * scale));
718 UInt E5 = (As<UInt>(max_s) >> 23) - 127 + 15 + 1;
719
720 UInt E5B9G9R9 = (E5 << 27) | (B9 << 18) | (G9 << 9) | R9;
721
722 *Pointer<UInt>(element) = E5B9G9R9;
723 }
724 break;
Ben Claytonfccfc562019-12-17 20:37:31 +0000725 case VK_FORMAT_B8G8R8A8_SNORM:
726 if(writeB) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.z))); }
727 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
728 if(writeR) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.x))); }
729 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
730 break;
731 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
732 case VK_FORMAT_R8G8B8A8_SINT:
733 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
734 case VK_FORMAT_R8G8B8A8_SNORM:
735 case VK_FORMAT_R8G8B8A8_SSCALED:
736 case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
737 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500738 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000739 case VK_FORMAT_R8G8B8_SINT:
740 case VK_FORMAT_R8G8B8_SNORM:
741 case VK_FORMAT_R8G8B8_SSCALED:
742 if(writeB) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.z))); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500743 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000744 case VK_FORMAT_R8G8_SINT:
745 case VK_FORMAT_R8G8_SNORM:
746 case VK_FORMAT_R8G8_SSCALED:
747 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500748 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000749 case VK_FORMAT_R8_SINT:
750 case VK_FORMAT_R8_SNORM:
751 case VK_FORMAT_R8_SSCALED:
752 if(writeR) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.x))); }
753 break;
754 case VK_FORMAT_R8G8B8_UINT:
755 case VK_FORMAT_R8G8B8_UNORM:
756 case VK_FORMAT_R8G8B8_USCALED:
757 case VK_FORMAT_R8G8B8_SRGB:
758 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500759 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000760 case VK_FORMAT_R8G8_UINT:
761 case VK_FORMAT_R8G8_UNORM:
762 case VK_FORMAT_R8G8_USCALED:
763 case VK_FORMAT_R8G8_SRGB:
764 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500765 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000766 case VK_FORMAT_R8_UINT:
767 case VK_FORMAT_R8_UNORM:
768 case VK_FORMAT_R8_USCALED:
769 case VK_FORMAT_R8_SRGB:
770 if(writeR) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x))); }
771 break;
772 case VK_FORMAT_R16G16B16A16_SINT:
773 case VK_FORMAT_R16G16B16A16_SNORM:
774 case VK_FORMAT_R16G16B16A16_SSCALED:
775 if(writeRGBA)
776 {
777 *Pointer<Short4>(element) = Short4(RoundInt(c));
778 }
779 else
780 {
781 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
782 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
783 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
784 if(writeA) { *Pointer<Short>(element + 6) = Short(RoundInt(Float(c.w))); }
785 }
786 break;
787 case VK_FORMAT_R16G16B16_SINT:
788 case VK_FORMAT_R16G16B16_SNORM:
789 case VK_FORMAT_R16G16B16_SSCALED:
Nicolas Capens157ba262019-12-10 17:49:14 -0500790 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
791 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
792 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
Ben Claytonfccfc562019-12-17 20:37:31 +0000793 break;
794 case VK_FORMAT_R16G16_SINT:
795 case VK_FORMAT_R16G16_SNORM:
796 case VK_FORMAT_R16G16_SSCALED:
797 if(writeR && writeG)
798 {
799 *Pointer<Short2>(element) = Short2(Short4(RoundInt(c)));
800 }
801 else
802 {
803 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
804 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
805 }
806 break;
807 case VK_FORMAT_R16_SINT:
808 case VK_FORMAT_R16_SNORM:
809 case VK_FORMAT_R16_SSCALED:
Nicolas Capens157ba262019-12-10 17:49:14 -0500810 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
Ben Claytonfccfc562019-12-17 20:37:31 +0000811 break;
812 case VK_FORMAT_R16G16B16A16_UINT:
813 case VK_FORMAT_R16G16B16A16_UNORM:
814 case VK_FORMAT_R16G16B16A16_USCALED:
815 if(writeRGBA)
816 {
817 *Pointer<UShort4>(element) = UShort4(RoundInt(c));
818 }
819 else
820 {
821 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
822 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
823 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
824 if(writeA) { *Pointer<UShort>(element + 6) = UShort(RoundInt(Float(c.w))); }
825 }
826 break;
827 case VK_FORMAT_R16G16B16_UINT:
828 case VK_FORMAT_R16G16B16_UNORM:
829 case VK_FORMAT_R16G16B16_USCALED:
Nicolas Capens157ba262019-12-10 17:49:14 -0500830 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
831 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
832 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
Ben Claytonfccfc562019-12-17 20:37:31 +0000833 break;
834 case VK_FORMAT_R16G16_UINT:
835 case VK_FORMAT_R16G16_UNORM:
836 case VK_FORMAT_R16G16_USCALED:
837 if(writeR && writeG)
838 {
839 *Pointer<UShort2>(element) = UShort2(UShort4(RoundInt(c)));
840 }
841 else
842 {
843 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
844 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
845 }
846 break;
847 case VK_FORMAT_R16_UINT:
848 case VK_FORMAT_R16_UNORM:
849 case VK_FORMAT_R16_USCALED:
Nicolas Capens157ba262019-12-10 17:49:14 -0500850 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
Ben Claytonfccfc562019-12-17 20:37:31 +0000851 break;
852 case VK_FORMAT_R32G32B32A32_SINT:
853 if(writeRGBA)
854 {
855 *Pointer<Int4>(element) = RoundInt(c);
856 }
857 else
858 {
859 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
860 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
861 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
862 if(writeA) { *Pointer<Int>(element + 12) = RoundInt(Float(c.w)); }
863 }
864 break;
865 case VK_FORMAT_R32G32B32_SINT:
Nicolas Capens157ba262019-12-10 17:49:14 -0500866 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500867 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000868 case VK_FORMAT_R32G32_SINT:
869 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500870 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000871 case VK_FORMAT_R32_SINT:
872 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
873 break;
874 case VK_FORMAT_R32G32B32A32_UINT:
875 if(writeRGBA)
876 {
877 *Pointer<UInt4>(element) = UInt4(RoundInt(c));
878 }
879 else
880 {
881 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
882 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
883 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
884 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(RoundInt(Float(c.w))); }
885 }
886 break;
887 case VK_FORMAT_R32G32B32_UINT:
Nicolas Capens157ba262019-12-10 17:49:14 -0500888 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500889 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000890 case VK_FORMAT_R32G32_UINT:
891 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
Nicolas Capens0405ba02020-01-16 01:19:21 -0500892 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +0000893 case VK_FORMAT_R32_UINT:
894 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
895 break;
896 case VK_FORMAT_R5G6B5_UNORM_PACK16:
897 if(writeR && writeG && writeB)
898 {
Alexis Hetu3716c202019-12-19 17:09:08 -0500899 *Pointer<UShort>(element) = UShort(PackFields(RoundInt(c.xyzz), { 11, 5, 0, 0 }));
Ben Claytonfccfc562019-12-17 20:37:31 +0000900 }
901 else
902 {
903 unsigned short mask = (writeB ? 0x001F : 0x0000) | (writeG ? 0x07E0 : 0x0000) | (writeR ? 0xF800 : 0x0000);
904 unsigned short unmask = ~mask;
905 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
Alexis Hetu3716c202019-12-19 17:09:08 -0500906 (UShort(PackFields(RoundInt(c.xyzz), { 11, 5, 0, 0 })) &
Ben Claytonfccfc562019-12-17 20:37:31 +0000907 UShort(mask));
908 }
909 break;
910 case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
911 if(writeRGBA)
912 {
Alexis Hetu3716c202019-12-19 17:09:08 -0500913 *Pointer<UShort>(element) = UShort(PackFields(RoundInt(c), { 11, 6, 1, 0 }));
Ben Claytonfccfc562019-12-17 20:37:31 +0000914 }
915 else
916 {
917 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
918 (writeR ? 0x7C00 : 0x0000) |
919 (writeG ? 0x03E0 : 0x0000) |
920 (writeB ? 0x001F : 0x0000);
921 unsigned short unmask = ~mask;
922 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
Alexis Hetu3716c202019-12-19 17:09:08 -0500923 (UShort(PackFields(RoundInt(c), { 11, 6, 1, 0 })) &
Ben Claytonfccfc562019-12-17 20:37:31 +0000924 UShort(mask));
925 }
926 break;
927 case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
928 if(writeRGBA)
929 {
Alexis Hetu3716c202019-12-19 17:09:08 -0500930 *Pointer<UShort>(element) = UShort(PackFields(RoundInt(c), { 1, 6, 11, 0 }));
Ben Claytonfccfc562019-12-17 20:37:31 +0000931 }
932 else
933 {
934 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
935 (writeR ? 0x7C00 : 0x0000) |
936 (writeG ? 0x03E0 : 0x0000) |
937 (writeB ? 0x001F : 0x0000);
938 unsigned short unmask = ~mask;
939 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
Alexis Hetu3716c202019-12-19 17:09:08 -0500940 (UShort(PackFields(RoundInt(c), { 1, 6, 11, 0 })) &
Ben Claytonfccfc562019-12-17 20:37:31 +0000941 UShort(mask));
942 }
943 break;
944 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
945 if(writeRGBA)
946 {
Alexis Hetu3716c202019-12-19 17:09:08 -0500947 *Pointer<UShort>(element) = UShort(PackFields(RoundInt(c), { 10, 5, 0, 15 }));
Ben Claytonfccfc562019-12-17 20:37:31 +0000948 }
949 else
950 {
951 unsigned short mask = (writeA ? 0x8000 : 0x0000) |
952 (writeR ? 0x7C00 : 0x0000) |
953 (writeG ? 0x03E0 : 0x0000) |
954 (writeB ? 0x001F : 0x0000);
955 unsigned short unmask = ~mask;
956 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
Alexis Hetu3716c202019-12-19 17:09:08 -0500957 (UShort(PackFields(RoundInt(c), { 10, 5, 0, 15 })) &
Ben Claytonfccfc562019-12-17 20:37:31 +0000958 UShort(mask));
959 }
960 break;
961 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
962 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
963 case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
964 if(writeRGBA)
965 {
Alexis Hetu3716c202019-12-19 17:09:08 -0500966 *Pointer<UInt>(element) = As<UInt>(PackFields(RoundInt(c), { 0, 10, 20, 30 }));
Ben Claytonfccfc562019-12-17 20:37:31 +0000967 }
968 else
969 {
970 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
971 (writeB ? 0x3FF00000 : 0x0000) |
972 (writeG ? 0x000FFC00 : 0x0000) |
973 (writeR ? 0x000003FF : 0x0000);
974 unsigned int unmask = ~mask;
975 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
Alexis Hetu3716c202019-12-19 17:09:08 -0500976 (As<UInt>(PackFields(RoundInt(c), { 0, 10, 20, 30 })) &
Ben Claytonfccfc562019-12-17 20:37:31 +0000977 UInt(mask));
978 }
979 break;
980 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
981 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
982 case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
983 if(writeRGBA)
984 {
Alexis Hetu3716c202019-12-19 17:09:08 -0500985 *Pointer<UInt>(element) = As<UInt>(PackFields(RoundInt(c), { 20, 10, 0, 30 }));
Ben Claytonfccfc562019-12-17 20:37:31 +0000986 }
987 else
988 {
989 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
990 (writeR ? 0x3FF00000 : 0x0000) |
991 (writeG ? 0x000FFC00 : 0x0000) |
992 (writeB ? 0x000003FF : 0x0000);
993 unsigned int unmask = ~mask;
994 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
Alexis Hetu3716c202019-12-19 17:09:08 -0500995 (As<UInt>(PackFields(RoundInt(c), { 20, 10, 0, 30 })) &
Ben Claytonfccfc562019-12-17 20:37:31 +0000996 UInt(mask));
997 }
998 break;
999 case VK_FORMAT_D16_UNORM:
1000 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x)));
1001 break;
1002 case VK_FORMAT_X8_D24_UNORM_PACK32:
1003 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) << 8);
1004 break;
1005 case VK_FORMAT_D32_SFLOAT:
1006 *Pointer<Float>(element) = c.x;
1007 break;
1008 case VK_FORMAT_S8_UINT:
1009 *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
1010 break;
1011 default:
1012 UNSUPPORTED("Blitter destination format %d", (int)state.destFormat);
1013 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001014 }
1015}
1016
1017Int4 Blitter::readInt4(Pointer<Byte> element, const State &state)
1018{
1019 Int4 c(0, 0, 0, 1);
1020
1021 switch(state.sourceFormat)
1022 {
Ben Claytonfccfc562019-12-17 20:37:31 +00001023 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1024 case VK_FORMAT_R8G8B8A8_SINT:
1025 c = Insert(c, Int(*Pointer<SByte>(element + 3)), 3);
1026 c = Insert(c, Int(*Pointer<SByte>(element + 2)), 2);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001027 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001028 case VK_FORMAT_R8G8_SINT:
1029 c = Insert(c, Int(*Pointer<SByte>(element + 1)), 1);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001030 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001031 case VK_FORMAT_R8_SINT:
1032 c = Insert(c, Int(*Pointer<SByte>(element)), 0);
1033 break;
1034 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1035 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000003FF))), 0);
1036 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10), 1);
1037 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20), 2);
1038 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30), 3);
1039 break;
Alexis Hetub8a61bf2020-01-09 15:26:34 -05001040 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1041 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000003FF))), 2);
1042 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10), 1);
1043 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20), 0);
1044 c = Insert(c, Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30), 3);
1045 break;
Ben Claytonfccfc562019-12-17 20:37:31 +00001046 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1047 case VK_FORMAT_R8G8B8A8_UINT:
1048 c = Insert(c, Int(*Pointer<Byte>(element + 3)), 3);
1049 c = Insert(c, Int(*Pointer<Byte>(element + 2)), 2);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001050 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001051 case VK_FORMAT_R8G8_UINT:
1052 c = Insert(c, Int(*Pointer<Byte>(element + 1)), 1);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001053 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001054 case VK_FORMAT_R8_UINT:
1055 case VK_FORMAT_S8_UINT:
1056 c = Insert(c, Int(*Pointer<Byte>(element)), 0);
1057 break;
1058 case VK_FORMAT_R16G16B16A16_SINT:
1059 c = Insert(c, Int(*Pointer<Short>(element + 6)), 3);
1060 c = Insert(c, Int(*Pointer<Short>(element + 4)), 2);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001061 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001062 case VK_FORMAT_R16G16_SINT:
1063 c = Insert(c, Int(*Pointer<Short>(element + 2)), 1);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001064 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001065 case VK_FORMAT_R16_SINT:
1066 c = Insert(c, Int(*Pointer<Short>(element)), 0);
1067 break;
1068 case VK_FORMAT_R16G16B16A16_UINT:
1069 c = Insert(c, Int(*Pointer<UShort>(element + 6)), 3);
1070 c = Insert(c, Int(*Pointer<UShort>(element + 4)), 2);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001071 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001072 case VK_FORMAT_R16G16_UINT:
1073 c = Insert(c, Int(*Pointer<UShort>(element + 2)), 1);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001074 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001075 case VK_FORMAT_R16_UINT:
1076 c = Insert(c, Int(*Pointer<UShort>(element)), 0);
1077 break;
1078 case VK_FORMAT_R32G32B32A32_SINT:
1079 case VK_FORMAT_R32G32B32A32_UINT:
1080 c = *Pointer<Int4>(element);
1081 break;
1082 case VK_FORMAT_R32G32_SINT:
1083 case VK_FORMAT_R32G32_UINT:
1084 c = Insert(c, *Pointer<Int>(element + 4), 1);
Nicolas Capens0405ba02020-01-16 01:19:21 -05001085 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001086 case VK_FORMAT_R32_SINT:
1087 case VK_FORMAT_R32_UINT:
1088 c = Insert(c, *Pointer<Int>(element), 0);
1089 break;
1090 default:
1091 UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
Nicolas Capens157ba262019-12-10 17:49:14 -05001092 }
1093
1094 return c;
1095}
1096
1097void Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
1098{
1099 bool writeR = state.writeRed;
1100 bool writeG = state.writeGreen;
1101 bool writeB = state.writeBlue;
1102 bool writeA = state.writeAlpha;
1103 bool writeRGBA = writeR && writeG && writeB && writeA;
1104
1105 switch(state.destFormat)
1106 {
Ben Claytonfccfc562019-12-17 20:37:31 +00001107 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Alexis Hetub8a61bf2020-01-09 15:26:34 -05001108 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
Ben Claytonfccfc562019-12-17 20:37:31 +00001109 c = Min(As<UInt4>(c), UInt4(0x03FF, 0x03FF, 0x03FF, 0x0003));
1110 break;
1111 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1112 case VK_FORMAT_R8G8B8A8_UINT:
1113 case VK_FORMAT_R8G8B8_UINT:
1114 case VK_FORMAT_R8G8_UINT:
1115 case VK_FORMAT_R8_UINT:
1116 case VK_FORMAT_R8G8B8A8_USCALED:
1117 case VK_FORMAT_R8G8B8_USCALED:
1118 case VK_FORMAT_R8G8_USCALED:
1119 case VK_FORMAT_R8_USCALED:
1120 case VK_FORMAT_S8_UINT:
1121 c = Min(As<UInt4>(c), UInt4(0xFF));
1122 break;
1123 case VK_FORMAT_R16G16B16A16_UINT:
1124 case VK_FORMAT_R16G16B16_UINT:
1125 case VK_FORMAT_R16G16_UINT:
1126 case VK_FORMAT_R16_UINT:
1127 case VK_FORMAT_R16G16B16A16_USCALED:
1128 case VK_FORMAT_R16G16B16_USCALED:
1129 case VK_FORMAT_R16G16_USCALED:
1130 case VK_FORMAT_R16_USCALED:
1131 c = Min(As<UInt4>(c), UInt4(0xFFFF));
1132 break;
1133 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1134 case VK_FORMAT_R8G8B8A8_SINT:
1135 case VK_FORMAT_R8G8_SINT:
1136 case VK_FORMAT_R8_SINT:
1137 case VK_FORMAT_R8G8B8A8_SSCALED:
1138 case VK_FORMAT_R8G8B8_SSCALED:
1139 case VK_FORMAT_R8G8_SSCALED:
1140 case VK_FORMAT_R8_SSCALED:
1141 c = Min(Max(c, Int4(-0x80)), Int4(0x7F));
1142 break;
1143 case VK_FORMAT_R16G16B16A16_SINT:
1144 case VK_FORMAT_R16G16B16_SINT:
1145 case VK_FORMAT_R16G16_SINT:
1146 case VK_FORMAT_R16_SINT:
1147 case VK_FORMAT_R16G16B16A16_SSCALED:
1148 case VK_FORMAT_R16G16B16_SSCALED:
1149 case VK_FORMAT_R16G16_SSCALED:
1150 case VK_FORMAT_R16_SSCALED:
1151 c = Min(Max(c, Int4(-0x8000)), Int4(0x7FFF));
1152 break;
1153 default:
1154 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001155 }
1156
1157 switch(state.destFormat)
1158 {
Ben Claytonfccfc562019-12-17 20:37:31 +00001159 case VK_FORMAT_B8G8R8A8_SINT:
1160 case VK_FORMAT_B8G8R8A8_SSCALED:
1161 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001162 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001163 case VK_FORMAT_B8G8R8_SINT:
1164 case VK_FORMAT_B8G8R8_SSCALED:
1165 if(writeB) { *Pointer<SByte>(element) = SByte(Extract(c, 2)); }
1166 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
1167 if(writeR) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 0)); }
1168 break;
1169 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1170 case VK_FORMAT_R8G8B8A8_SINT:
1171 case VK_FORMAT_R8G8B8A8_SSCALED:
1172 case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
1173 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001174 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001175 case VK_FORMAT_R8G8B8_SINT:
1176 case VK_FORMAT_R8G8B8_SSCALED:
1177 if(writeB) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 2)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001178 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001179 case VK_FORMAT_R8G8_SINT:
1180 case VK_FORMAT_R8G8_SSCALED:
1181 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001182 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001183 case VK_FORMAT_R8_SINT:
1184 case VK_FORMAT_R8_SSCALED:
1185 if(writeR) { *Pointer<SByte>(element) = SByte(Extract(c, 0)); }
1186 break;
1187 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1188 case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1189 case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
1190 case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
1191 if(writeRGBA)
1192 {
Alexis Hetu3716c202019-12-19 17:09:08 -05001193 *Pointer<UInt>(element) = As<UInt>(PackFields(c, { 0, 10, 20, 30 }));
Ben Claytonfccfc562019-12-17 20:37:31 +00001194 }
1195 else
1196 {
1197 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1198 (writeB ? 0x3FF00000 : 0x0000) |
1199 (writeG ? 0x000FFC00 : 0x0000) |
1200 (writeR ? 0x000003FF : 0x0000);
1201 unsigned int unmask = ~mask;
1202 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
Alexis Hetu3716c202019-12-19 17:09:08 -05001203 (As<UInt>(PackFields(c, { 0, 10, 20, 30 })) & UInt(mask));
Ben Claytonfccfc562019-12-17 20:37:31 +00001204 }
1205 break;
1206 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1207 case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1208 case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
1209 case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
1210 if(writeRGBA)
1211 {
Alexis Hetu3716c202019-12-19 17:09:08 -05001212 *Pointer<UInt>(element) = As<UInt>(PackFields(c, { 20, 10, 0, 30 }));
Ben Claytonfccfc562019-12-17 20:37:31 +00001213 }
1214 else
1215 {
1216 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
1217 (writeR ? 0x3FF00000 : 0x0000) |
1218 (writeG ? 0x000FFC00 : 0x0000) |
1219 (writeB ? 0x000003FF : 0x0000);
1220 unsigned int unmask = ~mask;
1221 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
Alexis Hetu3716c202019-12-19 17:09:08 -05001222 (As<UInt>(PackFields(c, { 20, 10, 0, 30 })) & UInt(mask));
Ben Claytonfccfc562019-12-17 20:37:31 +00001223 }
1224 break;
1225 case VK_FORMAT_B8G8R8A8_UINT:
1226 case VK_FORMAT_B8G8R8A8_USCALED:
1227 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001228 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001229 case VK_FORMAT_B8G8R8_UINT:
1230 case VK_FORMAT_B8G8R8_USCALED:
1231 case VK_FORMAT_B8G8R8_SRGB:
1232 if(writeB) { *Pointer<Byte>(element) = Byte(Extract(c, 2)); }
1233 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
1234 if(writeR) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 0)); }
1235 break;
1236 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1237 case VK_FORMAT_R8G8B8A8_UINT:
1238 case VK_FORMAT_R8G8B8A8_USCALED:
1239 case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
1240 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001241 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001242 case VK_FORMAT_R8G8B8_UINT:
1243 case VK_FORMAT_R8G8B8_USCALED:
1244 if(writeB) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 2)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001245 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001246 case VK_FORMAT_R8G8_UINT:
1247 case VK_FORMAT_R8G8_USCALED:
1248 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001249 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001250 case VK_FORMAT_R8_UINT:
1251 case VK_FORMAT_R8_USCALED:
1252 case VK_FORMAT_S8_UINT:
1253 if(writeR) { *Pointer<Byte>(element) = Byte(Extract(c, 0)); }
1254 break;
1255 case VK_FORMAT_R16G16B16A16_SINT:
1256 case VK_FORMAT_R16G16B16A16_SSCALED:
1257 if(writeA) { *Pointer<Short>(element + 6) = Short(Extract(c, 3)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001258 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001259 case VK_FORMAT_R16G16B16_SINT:
1260 case VK_FORMAT_R16G16B16_SSCALED:
1261 if(writeB) { *Pointer<Short>(element + 4) = Short(Extract(c, 2)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001262 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001263 case VK_FORMAT_R16G16_SINT:
1264 case VK_FORMAT_R16G16_SSCALED:
1265 if(writeG) { *Pointer<Short>(element + 2) = Short(Extract(c, 1)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001266 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001267 case VK_FORMAT_R16_SINT:
1268 case VK_FORMAT_R16_SSCALED:
1269 if(writeR) { *Pointer<Short>(element) = Short(Extract(c, 0)); }
1270 break;
1271 case VK_FORMAT_R16G16B16A16_UINT:
1272 case VK_FORMAT_R16G16B16A16_USCALED:
1273 if(writeA) { *Pointer<UShort>(element + 6) = UShort(Extract(c, 3)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001274 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001275 case VK_FORMAT_R16G16B16_UINT:
1276 case VK_FORMAT_R16G16B16_USCALED:
1277 if(writeB) { *Pointer<UShort>(element + 4) = UShort(Extract(c, 2)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001278 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001279 case VK_FORMAT_R16G16_UINT:
1280 case VK_FORMAT_R16G16_USCALED:
1281 if(writeG) { *Pointer<UShort>(element + 2) = UShort(Extract(c, 1)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001282 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001283 case VK_FORMAT_R16_UINT:
1284 case VK_FORMAT_R16_USCALED:
1285 if(writeR) { *Pointer<UShort>(element) = UShort(Extract(c, 0)); }
1286 break;
1287 case VK_FORMAT_R32G32B32A32_SINT:
1288 if(writeRGBA)
1289 {
1290 *Pointer<Int4>(element) = c;
1291 }
1292 else
1293 {
1294 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1295 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1296 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
1297 if(writeA) { *Pointer<Int>(element + 12) = Extract(c, 3); }
1298 }
1299 break;
1300 case VK_FORMAT_R32G32B32_SINT:
Nicolas Capens157ba262019-12-10 17:49:14 -05001301 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1302 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1303 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
Ben Claytonfccfc562019-12-17 20:37:31 +00001304 break;
1305 case VK_FORMAT_R32G32_SINT:
1306 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1307 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
1308 break;
1309 case VK_FORMAT_R32_SINT:
1310 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
1311 break;
1312 case VK_FORMAT_R32G32B32A32_UINT:
1313 if(writeRGBA)
1314 {
1315 *Pointer<UInt4>(element) = As<UInt4>(c);
1316 }
1317 else
1318 {
1319 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1320 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
1321 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
1322 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(Extract(c, 3)); }
1323 }
1324 break;
1325 case VK_FORMAT_R32G32B32_UINT:
Nicolas Capens157ba262019-12-10 17:49:14 -05001326 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001327 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001328 case VK_FORMAT_R32G32_UINT:
1329 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
Nicolas Capens0405ba02020-01-16 01:19:21 -05001330 // [[fallthrough]]
Ben Claytonfccfc562019-12-17 20:37:31 +00001331 case VK_FORMAT_R32_UINT:
1332 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
1333 break;
1334 default:
1335 UNSUPPORTED("Blitter destination format %d", (int)state.destFormat);
Nicolas Capens157ba262019-12-10 17:49:14 -05001336 }
1337}
1338
1339void Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
1340{
1341 float4 scale{}, unscale{};
1342
1343 if(state.clearOperation &&
Nicolas Capens9d9f30d2020-01-12 03:26:18 -05001344 state.sourceFormat.isUnnormalizedInteger() &&
1345 !state.destFormat.isUnnormalizedInteger())
Nicolas Capens157ba262019-12-10 17:49:14 -05001346 {
1347 // If we're clearing a buffer from an int or uint color into a normalized color,
1348 // then the whole range of the int or uint color must be scaled between 0 and 1.
1349 switch(state.sourceFormat)
1350 {
Ben Claytonfccfc562019-12-17 20:37:31 +00001351 case VK_FORMAT_R32G32B32A32_SINT:
1352 unscale = float4(static_cast<float>(0x7FFFFFFF));
1353 break;
1354 case VK_FORMAT_R32G32B32A32_UINT:
1355 unscale = float4(static_cast<float>(0xFFFFFFFF));
1356 break;
1357 default:
1358 UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
Nicolas Capens157ba262019-12-10 17:49:14 -05001359 }
1360 }
1361 else
1362 {
1363 unscale = state.sourceFormat.getScale();
1364 }
1365
1366 scale = state.destFormat.getScale();
1367
1368 bool srcSRGB = state.sourceFormat.isSRGBformat();
1369 bool dstSRGB = state.destFormat.isSRGBformat();
1370
Ben Claytonfccfc562019-12-17 20:37:31 +00001371 if(state.allowSRGBConversion && ((srcSRGB && !preScaled) || dstSRGB)) // One of the formats is sRGB encoded.
Nicolas Capens157ba262019-12-10 17:49:14 -05001372 {
Ben Claytonfccfc562019-12-17 20:37:31 +00001373 value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) : // Unapply scale
1374 Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w); // Apply unscale
Nicolas Capens157ba262019-12-10 17:49:14 -05001375 value = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : LinearToSRGB(value);
Ben Claytonfccfc562019-12-17 20:37:31 +00001376 value *= Float4(scale.x, scale.y, scale.z, scale.w); // Apply scale
Nicolas Capens157ba262019-12-10 17:49:14 -05001377 }
1378 else if(unscale != scale)
1379 {
1380 value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
1381 }
1382
1383 if(state.sourceFormat.isFloatFormat() && !state.destFormat.isFloatFormat())
1384 {
1385 value = Min(value, Float4(scale.x, scale.y, scale.z, scale.w));
1386
1387 value = Max(value, Float4(state.destFormat.isUnsignedComponent(0) ? 0.0f : -scale.x,
1388 state.destFormat.isUnsignedComponent(1) ? 0.0f : -scale.y,
1389 state.destFormat.isUnsignedComponent(2) ? 0.0f : -scale.z,
1390 state.destFormat.isUnsignedComponent(3) ? 0.0f : -scale.w));
1391 }
1392}
1393
1394Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes)
1395{
1396 return y * pitchB + x * bytes;
1397}
1398
Alexis Hetu18daa812020-03-11 17:06:53 -04001399Int Blitter::ComputeOffset(Int &x, Int &y, Int &z, Int &sliceB, Int &pitchB, int bytes)
1400{
1401 return z * sliceB + y * pitchB + x * bytes;
1402}
1403
Nicolas Capens2883de92020-01-27 14:58:14 -05001404Float4 Blitter::LinearToSRGB(const Float4 &c)
Nicolas Capens157ba262019-12-10 17:49:14 -05001405{
1406 Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
1407 Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
1408
1409 Float4 s = c;
1410 s.xyz = Max(lc, ec);
1411
1412 return s;
1413}
1414
Nicolas Capens2883de92020-01-27 14:58:14 -05001415Float4 Blitter::sRGBtoLinear(const Float4 &c)
Nicolas Capens157ba262019-12-10 17:49:14 -05001416{
1417 Float4 lc = c * Float4(1.0f / 12.92f);
1418 Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
1419
1420 Int4 linear = CmpLT(c, Float4(0.04045f));
1421
1422 Float4 s = c;
Ben Claytonfccfc562019-12-17 20:37:31 +00001423 s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec))); // TODO: IfThenElse()
Nicolas Capens157ba262019-12-10 17:49:14 -05001424
1425 return s;
1426}
1427
Alexis Hetu18daa812020-03-11 17:06:53 -04001428Float4 Blitter::sample(Pointer<Byte> &source, Float &x, Float &y, Float &z,
1429 Int &sWidth, Int &sHeight, Int &sDepth,
1430 Int &sSliceB, Int &sPitchB, const State &state)
1431{
1432 bool intSrc = state.sourceFormat.isUnnormalizedInteger();
1433 int srcBytes = state.sourceFormat.bytes();
1434
1435 Float4 color;
1436
1437 bool preScaled = false;
1438 if(!state.filter || intSrc)
1439 {
1440 Int X = Int(x);
1441 Int Y = Int(y);
1442 Int Z = Int(z);
1443
1444 if(state.clampToEdge)
1445 {
1446 X = Clamp(X, 0, sWidth - 1);
1447 Y = Clamp(Y, 0, sHeight - 1);
1448 Z = Clamp(Z, 0, sDepth - 1);
1449 }
1450
1451 Pointer<Byte> s = source + ComputeOffset(X, Y, Z, sSliceB, sPitchB, srcBytes);
1452
1453 color = readFloat4(s, state);
1454
1455 if(state.srcSamples > 1) // Resolve multisampled source
1456 {
1457 if(state.allowSRGBConversion && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1458 {
1459 ApplyScaleAndClamp(color, state);
1460 preScaled = true;
1461 }
1462 Float4 accum = color;
1463 for(int sample = 1; sample < state.srcSamples; sample++)
1464 {
1465 s += sSliceB;
1466 color = readFloat4(s, state);
1467
1468 if(state.allowSRGBConversion && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1469 {
1470 ApplyScaleAndClamp(color, state);
1471 preScaled = true;
1472 }
1473 accum += color;
1474 }
1475 color = accum * Float4(1.0f / static_cast<float>(state.srcSamples));
1476 }
1477 }
1478 else // Bilinear filtering
1479 {
1480 Float X = x;
1481 Float Y = y;
1482 Float Z = z;
1483
1484 if(state.clampToEdge)
1485 {
1486 X = Min(Max(x, 0.5f), Float(sWidth) - 0.5f);
1487 Y = Min(Max(y, 0.5f), Float(sHeight) - 0.5f);
1488 Z = Min(Max(z, 0.5f), Float(sDepth) - 0.5f);
1489 }
1490
1491 Float x0 = X - 0.5f;
1492 Float y0 = Y - 0.5f;
1493 Float z0 = Z - 0.5f;
1494
1495 Int X0 = Max(Int(x0), 0);
1496 Int Y0 = Max(Int(y0), 0);
1497 Int Z0 = Max(Int(z0), 0);
1498
1499 Int X1 = X0 + 1;
1500 Int Y1 = Y0 + 1;
1501 X1 = IfThenElse(X1 >= sWidth, X0, X1);
1502 Y1 = IfThenElse(Y1 >= sHeight, Y0, Y1);
1503
1504 if(state.filter3D)
1505 {
1506 Int Z1 = Z0 + 1;
1507 Z1 = IfThenElse(Z1 >= sHeight, Z0, Z1);
1508
1509 Pointer<Byte> s000 = source + ComputeOffset(X0, Y0, Z0, sSliceB, sPitchB, srcBytes);
1510 Pointer<Byte> s010 = source + ComputeOffset(X1, Y0, Z0, sSliceB, sPitchB, srcBytes);
1511 Pointer<Byte> s100 = source + ComputeOffset(X0, Y1, Z0, sSliceB, sPitchB, srcBytes);
1512 Pointer<Byte> s110 = source + ComputeOffset(X1, Y1, Z0, sSliceB, sPitchB, srcBytes);
1513 Pointer<Byte> s001 = source + ComputeOffset(X0, Y0, Z1, sSliceB, sPitchB, srcBytes);
1514 Pointer<Byte> s011 = source + ComputeOffset(X1, Y0, Z1, sSliceB, sPitchB, srcBytes);
1515 Pointer<Byte> s101 = source + ComputeOffset(X0, Y1, Z1, sSliceB, sPitchB, srcBytes);
1516 Pointer<Byte> s111 = source + ComputeOffset(X1, Y1, Z1, sSliceB, sPitchB, srcBytes);
1517
1518 Float4 c000 = readFloat4(s000, state);
1519 Float4 c010 = readFloat4(s010, state);
1520 Float4 c100 = readFloat4(s100, state);
1521 Float4 c110 = readFloat4(s110, state);
1522 Float4 c001 = readFloat4(s001, state);
1523 Float4 c011 = readFloat4(s011, state);
1524 Float4 c101 = readFloat4(s101, state);
1525 Float4 c111 = readFloat4(s111, state);
1526
1527 if(state.allowSRGBConversion && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1528 {
1529 ApplyScaleAndClamp(c000, state);
1530 ApplyScaleAndClamp(c010, state);
1531 ApplyScaleAndClamp(c100, state);
1532 ApplyScaleAndClamp(c110, state);
1533 ApplyScaleAndClamp(c001, state);
1534 ApplyScaleAndClamp(c011, state);
1535 ApplyScaleAndClamp(c101, state);
1536 ApplyScaleAndClamp(c111, state);
1537 preScaled = true;
1538 }
1539
1540 Float4 fx = Float4(x0 - Float(X0));
1541 Float4 fy = Float4(y0 - Float(Y0));
1542 Float4 fz = Float4(z0 - Float(Z0));
1543 Float4 ix = Float4(1.0f) - fx;
1544 Float4 iy = Float4(1.0f) - fy;
1545 Float4 iz = Float4(1.0f) - fz;
1546
1547 color = ((c000 * ix + c010 * fx) * iy +
1548 (c100 * ix + c110 * fx) * fy) *
1549 iz +
1550 ((c001 * ix + c011 * fx) * iy +
1551 (c101 * ix + c111 * fx) * fy) *
1552 fz;
1553 }
1554 else
1555 {
1556 Pointer<Byte> s00 = source + ComputeOffset(X0, Y0, Z0, sSliceB, sPitchB, srcBytes);
1557 Pointer<Byte> s01 = source + ComputeOffset(X1, Y0, Z0, sSliceB, sPitchB, srcBytes);
1558 Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, Z0, sSliceB, sPitchB, srcBytes);
1559 Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, Z0, sSliceB, sPitchB, srcBytes);
1560
1561 Float4 c00 = readFloat4(s00, state);
1562 Float4 c01 = readFloat4(s01, state);
1563 Float4 c10 = readFloat4(s10, state);
1564 Float4 c11 = readFloat4(s11, state);
1565
1566 if(state.allowSRGBConversion && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
1567 {
1568 ApplyScaleAndClamp(c00, state);
1569 ApplyScaleAndClamp(c01, state);
1570 ApplyScaleAndClamp(c10, state);
1571 ApplyScaleAndClamp(c11, state);
1572 preScaled = true;
1573 }
1574
1575 Float4 fx = Float4(x0 - Float(X0));
1576 Float4 fy = Float4(y0 - Float(Y0));
1577 Float4 ix = Float4(1.0f) - fx;
1578 Float4 iy = Float4(1.0f) - fy;
1579
1580 color = (c00 * ix + c01 * fx) * iy +
1581 (c10 * ix + c11 * fx) * fy;
1582 }
1583 }
1584
1585 ApplyScaleAndClamp(color, state, preScaled);
1586
1587 return color;
1588}
1589
Nicolas Capens157ba262019-12-10 17:49:14 -05001590Blitter::BlitRoutineType Blitter::generate(const State &state)
1591{
1592 BlitFunction function;
1593 {
1594 Pointer<Byte> blit(function.Arg<0>());
1595
Ben Claytonfccfc562019-12-17 20:37:31 +00001596 Pointer<Byte> source = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData, source));
1597 Pointer<Byte> dest = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData, dest));
1598 Int sPitchB = *Pointer<Int>(blit + OFFSET(BlitData, sPitchB));
1599 Int dPitchB = *Pointer<Int>(blit + OFFSET(BlitData, dPitchB));
Alexis Hetu18daa812020-03-11 17:06:53 -04001600 Int sSliceB = *Pointer<Int>(blit + OFFSET(BlitData, sSliceB));
1601 Int dSliceB = *Pointer<Int>(blit + OFFSET(BlitData, dSliceB));
Nicolas Capens157ba262019-12-10 17:49:14 -05001602
Ben Claytonfccfc562019-12-17 20:37:31 +00001603 Float x0 = *Pointer<Float>(blit + OFFSET(BlitData, x0));
1604 Float y0 = *Pointer<Float>(blit + OFFSET(BlitData, y0));
Alexis Hetu18daa812020-03-11 17:06:53 -04001605 Float z0 = *Pointer<Float>(blit + OFFSET(BlitData, z0));
Ben Claytonfccfc562019-12-17 20:37:31 +00001606 Float w = *Pointer<Float>(blit + OFFSET(BlitData, w));
1607 Float h = *Pointer<Float>(blit + OFFSET(BlitData, h));
Alexis Hetu18daa812020-03-11 17:06:53 -04001608 Float d = *Pointer<Float>(blit + OFFSET(BlitData, d));
Nicolas Capens157ba262019-12-10 17:49:14 -05001609
Ben Claytonfccfc562019-12-17 20:37:31 +00001610 Int x0d = *Pointer<Int>(blit + OFFSET(BlitData, x0d));
1611 Int x1d = *Pointer<Int>(blit + OFFSET(BlitData, x1d));
1612 Int y0d = *Pointer<Int>(blit + OFFSET(BlitData, y0d));
1613 Int y1d = *Pointer<Int>(blit + OFFSET(BlitData, y1d));
Alexis Hetu18daa812020-03-11 17:06:53 -04001614 Int z0d = *Pointer<Int>(blit + OFFSET(BlitData, z0d));
1615 Int z1d = *Pointer<Int>(blit + OFFSET(BlitData, z1d));
Nicolas Capens157ba262019-12-10 17:49:14 -05001616
Ben Claytonfccfc562019-12-17 20:37:31 +00001617 Int sWidth = *Pointer<Int>(blit + OFFSET(BlitData, sWidth));
1618 Int sHeight = *Pointer<Int>(blit + OFFSET(BlitData, sHeight));
Alexis Hetu18daa812020-03-11 17:06:53 -04001619 Int sDepth = *Pointer<Int>(blit + OFFSET(BlitData, sDepth));
Nicolas Capens157ba262019-12-10 17:49:14 -05001620
Nicolas Capens9d9f30d2020-01-12 03:26:18 -05001621 bool intSrc = state.sourceFormat.isUnnormalizedInteger();
1622 bool intDst = state.destFormat.isUnnormalizedInteger();
Nicolas Capens157ba262019-12-10 17:49:14 -05001623 bool intBoth = intSrc && intDst;
1624 int srcBytes = state.sourceFormat.bytes();
1625 int dstBytes = state.destFormat.bytes();
1626
1627 bool hasConstantColorI = false;
1628 Int4 constantColorI;
1629 bool hasConstantColorF = false;
1630 Float4 constantColorF;
1631 if(state.clearOperation)
1632 {
Ben Claytonfccfc562019-12-17 20:37:31 +00001633 if(intBoth) // Integer types
Nicolas Capens157ba262019-12-10 17:49:14 -05001634 {
1635 constantColorI = readInt4(source, state);
1636 hasConstantColorI = true;
1637 }
1638 else
1639 {
1640 constantColorF = readFloat4(source, state);
1641 hasConstantColorF = true;
1642
1643 ApplyScaleAndClamp(constantColorF, state);
1644 }
1645 }
1646
Alexis Hetu18daa812020-03-11 17:06:53 -04001647 For(Int k = z0d, k < z1d, k++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001648 {
Alexis Hetu18daa812020-03-11 17:06:53 -04001649 Float z = state.clearOperation ? RValue<Float>(z0) : z0 + Float(k) * d;
1650 Pointer<Byte> destSlice = dest + k * dSliceB;
Nicolas Capens157ba262019-12-10 17:49:14 -05001651
Alexis Hetu18daa812020-03-11 17:06:53 -04001652 For(Int j = y0d, j < y1d, j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001653 {
Alexis Hetu18daa812020-03-11 17:06:53 -04001654 Float y = state.clearOperation ? RValue<Float>(y0) : y0 + Float(j) * h;
1655 Pointer<Byte> destLine = destSlice + j * dPitchB;
Nicolas Capens157ba262019-12-10 17:49:14 -05001656
Alexis Hetu18daa812020-03-11 17:06:53 -04001657 For(Int i = x0d, i < x1d, i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001658 {
Alexis Hetu18daa812020-03-11 17:06:53 -04001659 Float x = state.clearOperation ? RValue<Float>(x0) : x0 + Float(i) * w;
1660 Pointer<Byte> d = destLine + i * dstBytes;
1661
1662 if(hasConstantColorI)
Nicolas Capens157ba262019-12-10 17:49:14 -05001663 {
Alexis Hetu18daa812020-03-11 17:06:53 -04001664 for(int s = 0; s < state.destSamples; s++)
1665 {
1666 write(constantColorI, d, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001667
Alexis Hetu18daa812020-03-11 17:06:53 -04001668 d += dSliceB;
1669 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001670 }
Alexis Hetu18daa812020-03-11 17:06:53 -04001671 else if(hasConstantColorF)
Nicolas Capens157ba262019-12-10 17:49:14 -05001672 {
Alexis Hetu18daa812020-03-11 17:06:53 -04001673 for(int s = 0; s < state.destSamples; s++)
1674 {
1675 write(constantColorF, d, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001676
Alexis Hetu18daa812020-03-11 17:06:53 -04001677 d += dSliceB;
1678 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001679 }
Alexis Hetu18daa812020-03-11 17:06:53 -04001680 else if(intBoth) // Integer types do not support filtering
Nicolas Capens68a82382018-10-02 13:16:55 -04001681 {
Nicolas Capens68a82382018-10-02 13:16:55 -04001682 Int X = Int(x);
1683 Int Y = Int(y);
Alexis Hetu18daa812020-03-11 17:06:53 -04001684 Int Z = Int(z);
Nicolas Capens68a82382018-10-02 13:16:55 -04001685
1686 if(state.clampToEdge)
1687 {
1688 X = Clamp(X, 0, sWidth - 1);
1689 Y = Clamp(Y, 0, sHeight - 1);
Alexis Hetu18daa812020-03-11 17:06:53 -04001690 Z = Clamp(Z, 0, sDepth - 1);
Nicolas Capens68a82382018-10-02 13:16:55 -04001691 }
1692
Alexis Hetu18daa812020-03-11 17:06:53 -04001693 Pointer<Byte> s = source + ComputeOffset(X, Y, Z, sSliceB, sPitchB, srcBytes);
Nicolas Capens68a82382018-10-02 13:16:55 -04001694
Alexis Hetu18daa812020-03-11 17:06:53 -04001695 // When both formats are true integer types, we don't go to float to avoid losing precision
1696 Int4 color = readInt4(s, state);
1697 for(int s = 0; s < state.destSamples; s++)
Alexis Hetuf8df30f2019-10-23 18:03:21 -04001698 {
Alexis Hetu18daa812020-03-11 17:06:53 -04001699 write(color, d, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001700
Alexis Hetu18daa812020-03-11 17:06:53 -04001701 d += dSliceB;
Nicolas Capens68a82382018-10-02 13:16:55 -04001702 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001703 }
Alexis Hetu18daa812020-03-11 17:06:53 -04001704 else
Nicolas Capens157ba262019-12-10 17:49:14 -05001705 {
Alexis Hetu18daa812020-03-11 17:06:53 -04001706 Float4 color = sample(source, x, y, z, sWidth, sHeight, sDepth, sSliceB, sPitchB, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001707
Alexis Hetu18daa812020-03-11 17:06:53 -04001708 for(int s = 0; s < state.destSamples; s++)
Nicolas Capens68a82382018-10-02 13:16:55 -04001709 {
Alexis Hetu18daa812020-03-11 17:06:53 -04001710 write(color, d, state);
1711
1712 d += dSliceB;
Nicolas Capens68a82382018-10-02 13:16:55 -04001713 }
Nicolas Capens68a82382018-10-02 13:16:55 -04001714 }
1715 }
1716 }
1717 }
Nicolas Capens68a82382018-10-02 13:16:55 -04001718 }
1719
Nicolas Capens157ba262019-12-10 17:49:14 -05001720 return function("BlitRoutine");
1721}
1722
1723Blitter::BlitRoutineType Blitter::getBlitRoutine(const State &state)
1724{
Ben Clayton377573c2020-04-03 20:36:40 +01001725 marl::lock lock(blitMutex);
Ben Claytonac43aa72020-04-04 00:48:13 +01001726 auto blitRoutine = blitCache.lookup(state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001727
1728 if(!blitRoutine)
Alexis Hetu33642272019-03-01 11:55:59 -05001729 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001730 blitRoutine = generate(state);
1731 blitCache.add(state, blitRoutine);
Alexis Hetu33642272019-03-01 11:55:59 -05001732 }
1733
Nicolas Capens157ba262019-12-10 17:49:14 -05001734 return blitRoutine;
1735}
1736
1737Blitter::CornerUpdateRoutineType Blitter::getCornerUpdateRoutine(const State &state)
1738{
Ben Clayton377573c2020-04-03 20:36:40 +01001739 marl::lock lock(cornerUpdateMutex);
Ben Claytonac43aa72020-04-04 00:48:13 +01001740 auto cornerUpdateRoutine = cornerUpdateCache.lookup(state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001741
1742 if(!cornerUpdateRoutine)
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001743 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001744 cornerUpdateRoutine = generateCornerUpdate(state);
1745 cornerUpdateCache.add(state, cornerUpdateRoutine);
Alexis Hetuf60a2d52019-05-09 14:16:05 -04001746 }
1747
Nicolas Capens157ba262019-12-10 17:49:14 -05001748 return cornerUpdateRoutine;
1749}
1750
Nicolas Capens157ba262019-12-10 17:49:14 -05001751void Blitter::blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter)
1752{
Nicolas Capens64ed1212020-08-26 14:05:28 -04001753 ASSERT(src->getFormat() != VK_FORMAT_UNDEFINED);
1754 ASSERT(dst->getFormat() != VK_FORMAT_UNDEFINED);
Nicolas Capens157ba262019-12-10 17:49:14 -05001755
Nicolas Capensdd0e6002020-01-24 01:21:47 -05001756 // Vulkan 1.2 section 18.5. Image Copies with Scaling:
1757 // "The layerCount member of srcSubresource and dstSubresource must match"
1758 // "The aspectMask member of srcSubresource and dstSubresource must match"
1759 ASSERT(region.srcSubresource.layerCount == region.dstSubresource.layerCount);
1760 ASSERT(region.srcSubresource.aspectMask == region.dstSubresource.aspectMask);
Nicolas Capens157ba262019-12-10 17:49:14 -05001761
1762 if(region.dstOffsets[0].x > region.dstOffsets[1].x)
1763 {
1764 std::swap(region.srcOffsets[0].x, region.srcOffsets[1].x);
1765 std::swap(region.dstOffsets[0].x, region.dstOffsets[1].x);
1766 }
1767
1768 if(region.dstOffsets[0].y > region.dstOffsets[1].y)
1769 {
1770 std::swap(region.srcOffsets[0].y, region.srcOffsets[1].y);
1771 std::swap(region.dstOffsets[0].y, region.dstOffsets[1].y);
1772 }
1773
Ari Suonpaa07118692020-06-02 12:17:00 +03001774 if(region.dstOffsets[0].z > region.dstOffsets[1].z)
1775 {
1776 std::swap(region.srcOffsets[0].z, region.srcOffsets[1].z);
1777 std::swap(region.dstOffsets[0].z, region.dstOffsets[1].z);
1778 }
1779
Nicolas Capens157ba262019-12-10 17:49:14 -05001780 VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask);
1781 VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask);
1782 VkExtent3D srcExtent = src->getMipLevelExtent(srcAspect, region.srcSubresource.mipLevel);
1783
Nicolas Capens157ba262019-12-10 17:49:14 -05001784 float widthRatio = static_cast<float>(region.srcOffsets[1].x - region.srcOffsets[0].x) /
1785 static_cast<float>(region.dstOffsets[1].x - region.dstOffsets[0].x);
1786 float heightRatio = static_cast<float>(region.srcOffsets[1].y - region.srcOffsets[0].y) /
1787 static_cast<float>(region.dstOffsets[1].y - region.dstOffsets[0].y);
Alexis Hetu18daa812020-03-11 17:06:53 -04001788 float depthRatio = static_cast<float>(region.srcOffsets[1].z - region.srcOffsets[0].z) /
1789 static_cast<float>(region.dstOffsets[1].z - region.dstOffsets[0].z);
Nicolas Capens157ba262019-12-10 17:49:14 -05001790 float x0 = region.srcOffsets[0].x + (0.5f - region.dstOffsets[0].x) * widthRatio;
1791 float y0 = region.srcOffsets[0].y + (0.5f - region.dstOffsets[0].y) * heightRatio;
Alexis Hetu18daa812020-03-11 17:06:53 -04001792 float z0 = region.srcOffsets[0].z + (0.5f - region.dstOffsets[0].z) * depthRatio;
Nicolas Capens157ba262019-12-10 17:49:14 -05001793
1794 auto srcFormat = src->getFormat(srcAspect);
1795 auto dstFormat = dst->getFormat(dstAspect);
1796
1797 bool doFilter = (filter != VK_FILTER_NEAREST);
1798 bool allowSRGBConversion =
Ben Claytonfccfc562019-12-17 20:37:31 +00001799 doFilter ||
1800 (src->getSampleCountFlagBits() > 1) ||
1801 (srcFormat.isSRGBformat() != dstFormat.isSRGBformat());
Nicolas Capens157ba262019-12-10 17:49:14 -05001802
1803 State state(src->getFormat(srcAspect), dst->getFormat(dstAspect), src->getSampleCountFlagBits(), dst->getSampleCountFlagBits(),
1804 Options{ doFilter, allowSRGBConversion });
1805 state.clampToEdge = (region.srcOffsets[0].x < 0) ||
1806 (region.srcOffsets[0].y < 0) ||
1807 (static_cast<uint32_t>(region.srcOffsets[1].x) > srcExtent.width) ||
1808 (static_cast<uint32_t>(region.srcOffsets[1].y) > srcExtent.height) ||
1809 (doFilter && ((x0 < 0.5f) || (y0 < 0.5f)));
Alexis Hetu18daa812020-03-11 17:06:53 -04001810 state.filter3D = (region.srcOffsets[1].z - region.srcOffsets[0].z) !=
1811 (region.dstOffsets[1].z - region.dstOffsets[0].z);
Nicolas Capens157ba262019-12-10 17:49:14 -05001812
1813 auto blitRoutine = getBlitRoutine(state);
1814 if(!blitRoutine)
1815 {
1816 return;
1817 }
1818
Ben Claytonfccfc562019-12-17 20:37:31 +00001819 BlitData data = {
1820 nullptr, // source
1821 nullptr, // dest
1822 src->rowPitchBytes(srcAspect, region.srcSubresource.mipLevel), // sPitchB
1823 dst->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel), // dPitchB
1824 src->slicePitchBytes(srcAspect, region.srcSubresource.mipLevel), // sSliceB
1825 dst->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel), // dSliceB
Nicolas Capens157ba262019-12-10 17:49:14 -05001826
1827 x0,
1828 y0,
Alexis Hetu18daa812020-03-11 17:06:53 -04001829 z0,
Nicolas Capens157ba262019-12-10 17:49:14 -05001830 widthRatio,
1831 heightRatio,
Alexis Hetu18daa812020-03-11 17:06:53 -04001832 depthRatio,
Nicolas Capens157ba262019-12-10 17:49:14 -05001833
Ben Claytonfccfc562019-12-17 20:37:31 +00001834 region.dstOffsets[0].x, // x0d
1835 region.dstOffsets[1].x, // x1d
Alexis Hetu18daa812020-03-11 17:06:53 -04001836 region.dstOffsets[0].y, // y0d
1837 region.dstOffsets[1].y, // y1d
1838 region.dstOffsets[0].z, // z0d
1839 region.dstOffsets[1].z, // z1d
Nicolas Capens157ba262019-12-10 17:49:14 -05001840
Alexis Hetu18daa812020-03-11 17:06:53 -04001841 static_cast<int>(srcExtent.width), // sWidth
1842 static_cast<int>(srcExtent.height), // sHeight
1843 static_cast<int>(srcExtent.depth), // sDepth
Ben Clayton21fb75f2020-04-16 10:36:55 +01001844
1845 false, // filter3D
Nicolas Capens157ba262019-12-10 17:49:14 -05001846 };
1847
Alexis Hetu46159712020-06-15 16:13:51 -04001848 VkImageSubresource srcSubres = {
Nicolas Capens157ba262019-12-10 17:49:14 -05001849 region.srcSubresource.aspectMask,
1850 region.srcSubresource.mipLevel,
Alexis Hetu46159712020-06-15 16:13:51 -04001851 region.srcSubresource.baseArrayLayer
Nicolas Capens157ba262019-12-10 17:49:14 -05001852 };
1853
Alexis Hetu46159712020-06-15 16:13:51 -04001854 VkImageSubresource dstSubres = {
Nicolas Capens157ba262019-12-10 17:49:14 -05001855 region.dstSubresource.aspectMask,
1856 region.dstSubresource.mipLevel,
Alexis Hetu46159712020-06-15 16:13:51 -04001857 region.dstSubresource.baseArrayLayer
Nicolas Capens157ba262019-12-10 17:49:14 -05001858 };
1859
Alexis Hetu46159712020-06-15 16:13:51 -04001860 VkImageSubresourceRange dstSubresRange = {
1861 region.dstSubresource.aspectMask,
1862 region.dstSubresource.mipLevel,
Nicolas Capens64ed1212020-08-26 14:05:28 -04001863 1, // levelCount
Alexis Hetu46159712020-06-15 16:13:51 -04001864 region.dstSubresource.baseArrayLayer,
1865 region.dstSubresource.layerCount
Nicolas Capens157ba262019-12-10 17:49:14 -05001866 };
1867
Alexis Hetu46159712020-06-15 16:13:51 -04001868 uint32_t lastLayer = src->getLastLayerIndex(dstSubresRange);
Nicolas Capens157ba262019-12-10 17:49:14 -05001869
Alexis Hetu46159712020-06-15 16:13:51 -04001870 for(; dstSubres.arrayLayer <= lastLayer; srcSubres.arrayLayer++, dstSubres.arrayLayer++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001871 {
Alexis Hetu46159712020-06-15 16:13:51 -04001872 data.source = src->getTexelPointer({ 0, 0, 0 }, srcSubres);
1873 data.dest = dst->getTexelPointer({ 0, 0, 0 }, dstSubres);
Nicolas Capens157ba262019-12-10 17:49:14 -05001874
Alexis Hetu18daa812020-03-11 17:06:53 -04001875 ASSERT(data.source < src->end());
1876 ASSERT(data.dest < dst->end());
Nicolas Capens157ba262019-12-10 17:49:14 -05001877
Alexis Hetu18daa812020-03-11 17:06:53 -04001878 blitRoutine(&data);
Nicolas Capens157ba262019-12-10 17:49:14 -05001879 }
Alexis Hetu4f438a52020-06-15 16:13:51 -04001880
1881 dst->contentsChanged(dstSubresRange);
Nicolas Capens157ba262019-12-10 17:49:14 -05001882}
1883
Sean Risser1d5174b2020-09-22 16:58:28 -04001884static void resolveDepth(const vk::ImageView *src, vk::ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsrDesc)
1885{
1886 if(dsrDesc.depthResolveMode == VK_RESOLVE_MODE_NONE)
1887 {
1888 return;
1889 }
1890
1891 vk::Format format = src->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT);
1892 VkExtent2D extent = src->getMipLevelExtent(0, VK_IMAGE_ASPECT_DEPTH_BIT);
1893 int width = extent.width;
1894 int height = extent.height;
1895 int pitch = src->rowPitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
1896
1897 // To support other resolve modes, get the slice bytes and get a pointer to each sample plane.
1898 // Then modify the loop below to include logic for handling each new mode.
1899 uint8_t *source = (uint8_t *)src->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0);
1900 uint8_t *dest = (uint8_t *)dst->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0);
1901
1902 size_t formatSize = format.bytes();
1903 // TODO(b/167558951) support other resolve modes.
1904 ASSERT(dsrDesc.depthResolveMode == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT);
1905 for(int y = 0; y < height; y++)
1906 {
1907 memcpy(dest, source, formatSize * width);
1908
1909 source += pitch;
1910 dest += pitch;
1911 }
1912
1913 dst->contentsChanged();
1914}
1915
1916static void resolveStencil(const vk::ImageView *src, vk::ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsrDesc)
1917{
1918 if(dsrDesc.stencilResolveMode == VK_RESOLVE_MODE_NONE)
1919 {
1920 return;
1921 }
1922
1923 VkExtent2D extent = src->getMipLevelExtent(0, VK_IMAGE_ASPECT_STENCIL_BIT);
1924 int width = extent.width;
1925 int height = extent.height;
1926 int pitch = src->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
1927
1928 // To support other resolve modes, use src->slicePitchBytes() and get a pointer to each sample's slice.
1929 // Then modify the loop below to include logic for handling each new mode.
1930 uint8_t *source = reinterpret_cast<uint8_t *>(src->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0));
1931 uint8_t *dest = reinterpret_cast<uint8_t *>(dst->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0));
1932
1933 // TODO(b/167558951) support other resolve modes.
1934 ASSERT(dsrDesc.stencilResolveMode == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT);
1935 for(int y = 0; y < height; y++)
1936 {
1937 // Stencil is always 8 bits, so the width of the resource we're resolving is
1938 // the number of bytes in each row we need to copy during for SAMPLE_ZERO
1939 memcpy(dest, source, width);
1940
1941 source += pitch;
1942 dest += pitch;
1943 }
1944
1945 dst->contentsChanged();
1946}
1947
1948void Blitter::resolveDepthStencil(const vk::ImageView *src, vk::ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsrDesc)
1949{
1950 VkImageSubresourceRange srcRange = src->getSubresourceRange();
1951 VkImageSubresourceRange dstRange = src->getSubresourceRange();
1952 ASSERT(src->getFormat() == dst->getFormat());
1953 ASSERT(srcRange.layerCount == 1 && dstRange.layerCount == 1);
1954 ASSERT(srcRange.aspectMask == dstRange.aspectMask);
1955
1956 if(srcRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
1957 {
1958 resolveDepth(src, dst, dsrDesc);
1959 }
1960 if(srcRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
1961 {
1962 resolveStencil(src, dst, dsrDesc);
1963 }
1964}
1965
Nicolas Capens64ed1212020-08-26 14:05:28 -04001966void Blitter::resolve(const vk::Image *src, vk::Image *dst, VkImageResolve region)
1967{
Nicolas Capens2d5bbdc2020-09-01 11:17:32 -04001968 // "The aspectMask member of srcSubresource and dstSubresource must only contain VK_IMAGE_ASPECT_COLOR_BIT"
1969 ASSERT(region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
1970 ASSERT(region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
1971 // "The layerCount member of srcSubresource and dstSubresource must match"
1972 ASSERT(region.srcSubresource.layerCount == region.dstSubresource.layerCount);
1973
1974 // We use this method both for explicit resolves from vkCmdResolveImage, and implicit ones for resolve attachments.
1975 // - vkCmdResolveImage: "srcImage and dstImage must have been created with the same image format."
1976 // - VkSubpassDescription: "each resolve attachment that is not VK_ATTACHMENT_UNUSED must have the same VkFormat as its corresponding color attachment."
1977 ASSERT(src->getFormat() == dst->getFormat());
1978
Nicolas Capens4487e582020-08-26 15:43:22 -04001979 if(fastResolve(src, dst, region))
1980 {
1981 return;
1982 }
1983
1984 // Fall back to a generic blit which performs the resolve.
Nicolas Capens64ed1212020-08-26 14:05:28 -04001985 VkImageBlit blitRegion;
1986
1987 blitRegion.srcOffsets[0] = blitRegion.srcOffsets[1] = region.srcOffset;
1988 blitRegion.srcOffsets[1].x += region.extent.width;
1989 blitRegion.srcOffsets[1].y += region.extent.height;
1990 blitRegion.srcOffsets[1].z += region.extent.depth;
1991
1992 blitRegion.dstOffsets[0] = blitRegion.dstOffsets[1] = region.dstOffset;
1993 blitRegion.dstOffsets[1].x += region.extent.width;
1994 blitRegion.dstOffsets[1].y += region.extent.height;
1995 blitRegion.dstOffsets[1].z += region.extent.depth;
1996
1997 blitRegion.srcSubresource = region.srcSubresource;
1998 blitRegion.dstSubresource = region.dstSubresource;
1999
2000 blit(src, dst, blitRegion, VK_FILTER_NEAREST);
2001}
2002
Nicolas Capens4487e582020-08-26 15:43:22 -04002003static inline uint32_t averageByte4(uint32_t x, uint32_t y)
2004{
2005 return (x & y) + (((x ^ y) >> 1) & 0x7F7F7F7F) + ((x ^ y) & 0x01010101);
2006}
2007
2008bool Blitter::fastResolve(const vk::Image *src, vk::Image *dst, VkImageResolve region)
2009{
Nicolas Capens4487e582020-08-26 15:43:22 -04002010 if(region.dstOffset != VkOffset3D{ 0, 0, 0 })
2011 {
2012 return false;
2013 }
2014
2015 if(region.srcOffset != VkOffset3D{ 0, 0, 0 })
2016 {
2017 return false;
2018 }
2019
2020 if(region.srcSubresource.layerCount != 1)
2021 {
2022 return false;
2023 }
2024
2025 if(region.extent != src->getExtent() ||
2026 region.extent != dst->getExtent() ||
2027 region.extent.depth != 1)
2028 {
2029 return false;
2030 }
2031
2032 VkImageSubresource srcSubresource = {
2033 region.srcSubresource.aspectMask,
2034 region.srcSubresource.mipLevel,
2035 region.srcSubresource.baseArrayLayer
2036 };
2037
2038 VkImageSubresource dstSubresource = {
2039 region.dstSubresource.aspectMask,
2040 region.dstSubresource.mipLevel,
2041 region.dstSubresource.baseArrayLayer
2042 };
2043
2044 VkImageSubresourceRange dstSubresourceRange = {
2045 region.dstSubresource.aspectMask,
2046 region.dstSubresource.mipLevel,
2047 1, // levelCount
2048 region.dstSubresource.baseArrayLayer,
2049 region.dstSubresource.layerCount
2050 };
2051
2052 void *source = src->getTexelPointer({ 0, 0, 0 }, srcSubresource);
2053 uint8_t *dest = reinterpret_cast<uint8_t *>(dst->getTexelPointer({ 0, 0, 0 }, dstSubresource));
2054
2055 auto format = src->getFormat();
2056 auto samples = src->getSampleCountFlagBits();
2057 auto extent = src->getExtent();
2058
2059 int width = extent.width;
2060 int height = extent.height;
2061 int pitch = src->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, region.srcSubresource.mipLevel);
2062 int slice = src->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, region.srcSubresource.mipLevel);
2063
2064 uint8_t *source0 = (uint8_t *)source;
2065 uint8_t *source1 = source0 + slice;
2066 uint8_t *source2 = source1 + slice;
2067 uint8_t *source3 = source2 + slice;
2068
Nicolas Capensb3e5c442021-01-20 06:16:24 +00002069 [[maybe_unused]] const bool SSE2 = CPUID::supportsSSE2();
Nicolas Capensa2e6c1a2020-08-26 15:44:50 -04002070
Nicolas Capens4487e582020-08-26 15:43:22 -04002071 if(format == VK_FORMAT_R8G8B8A8_UNORM || format == VK_FORMAT_B8G8R8A8_UNORM || format == VK_FORMAT_A8B8G8R8_UNORM_PACK32)
2072 {
2073 if(samples == 4)
2074 {
2075 for(int y = 0; y < height; y++)
2076 {
Nicolas Capensa2e6c1a2020-08-26 15:44:50 -04002077 int x = 0;
2078
2079#if defined(__i386__) || defined(__x86_64__)
2080 if(SSE2)
2081 {
2082 for(; (x + 3) < width; x += 4)
2083 {
2084 __m128i c0 = _mm_loadu_si128((__m128i *)(source0 + 4 * x));
2085 __m128i c1 = _mm_loadu_si128((__m128i *)(source1 + 4 * x));
2086 __m128i c2 = _mm_loadu_si128((__m128i *)(source2 + 4 * x));
2087 __m128i c3 = _mm_loadu_si128((__m128i *)(source3 + 4 * x));
2088
2089 c0 = _mm_avg_epu8(c0, c1);
2090 c2 = _mm_avg_epu8(c2, c3);
2091 c0 = _mm_avg_epu8(c0, c2);
2092
2093 _mm_storeu_si128((__m128i *)(dest + 4 * x), c0);
2094 }
2095 }
2096#endif
2097
2098 for(; x < width; x++)
Nicolas Capens4487e582020-08-26 15:43:22 -04002099 {
2100 uint32_t c0 = *(uint32_t *)(source0 + 4 * x);
2101 uint32_t c1 = *(uint32_t *)(source1 + 4 * x);
2102 uint32_t c2 = *(uint32_t *)(source2 + 4 * x);
2103 uint32_t c3 = *(uint32_t *)(source3 + 4 * x);
2104
2105 uint32_t c01 = averageByte4(c0, c1);
2106 uint32_t c23 = averageByte4(c2, c3);
2107 uint32_t c03 = averageByte4(c01, c23);
2108
2109 *(uint32_t *)(dest + 4 * x) = c03;
2110 }
2111
2112 source0 += pitch;
2113 source1 += pitch;
2114 source2 += pitch;
2115 source3 += pitch;
2116 dest += pitch;
Nicolas Capensa2e6c1a2020-08-26 15:44:50 -04002117
2118 ASSERT(source0 < src->end());
2119 ASSERT(source3 < src->end());
2120 ASSERT(dest < dst->end());
Nicolas Capens4487e582020-08-26 15:43:22 -04002121 }
2122 }
2123 else
2124 UNSUPPORTED("Samples: %d", samples);
2125 }
2126 else
2127 {
2128 return false;
2129 }
2130
2131 dst->contentsChanged(dstSubresourceRange);
2132
2133 return true;
2134}
2135
Nicolas Capens64ed1212020-08-26 14:05:28 -04002136void Blitter::copy(const vk::Image *src, uint8_t *dst, unsigned int dstPitch)
2137{
2138 VkExtent3D extent = src->getExtent();
2139 size_t rowBytes = src->getFormat(VK_IMAGE_ASPECT_COLOR_BIT).bytes() * extent.width;
2140 unsigned int srcPitch = src->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
2141 ASSERT(dstPitch >= rowBytes && srcPitch >= rowBytes && src->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0).height >= extent.height);
2142
2143 const uint8_t *s = (uint8_t *)src->getTexelPointer({ 0, 0, 0 }, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 });
2144 uint8_t *d = dst;
2145
2146 for(uint32_t y = 0; y < extent.height; y++)
2147 {
2148 memcpy(d, s, rowBytes);
2149
2150 s += srcPitch;
2151 d += dstPitch;
2152 }
2153}
2154
Ben Claytonfccfc562019-12-17 20:37:31 +00002155void Blitter::computeCubeCorner(Pointer<Byte> &layer, Int &x0, Int &x1, Int &y0, Int &y1, Int &pitchB, const State &state)
Nicolas Capens157ba262019-12-10 17:49:14 -05002156{
2157 int bytes = state.sourceFormat.bytes();
2158
2159 Float4 c = readFloat4(layer + ComputeOffset(x0, y1, pitchB, bytes), state) +
2160 readFloat4(layer + ComputeOffset(x1, y0, pitchB, bytes), state) +
2161 readFloat4(layer + ComputeOffset(x1, y1, pitchB, bytes), state);
2162
2163 c *= Float4(1.0f / 3.0f);
2164
2165 write(c, layer + ComputeOffset(x0, y0, pitchB, bytes), state);
2166}
2167
Ben Claytonfccfc562019-12-17 20:37:31 +00002168Blitter::CornerUpdateRoutineType Blitter::generateCornerUpdate(const State &state)
Nicolas Capens157ba262019-12-10 17:49:14 -05002169{
2170 // Reading and writing from/to the same image
2171 ASSERT(state.sourceFormat == state.destFormat);
2172 ASSERT(state.srcSamples == state.destSamples);
2173
Nicolas Capensdd0e6002020-01-24 01:21:47 -05002174 // Vulkan 1.2: "If samples is not VK_SAMPLE_COUNT_1_BIT, then imageType must be
2175 // VK_IMAGE_TYPE_2D, flags must not contain VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT"
2176 ASSERT(state.srcSamples == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002177
2178 CornerUpdateFunction function;
2179 {
2180 Pointer<Byte> blit(function.Arg<0>());
2181
2182 Pointer<Byte> layers = *Pointer<Pointer<Byte>>(blit + OFFSET(CubeBorderData, layers));
2183 Int pitchB = *Pointer<Int>(blit + OFFSET(CubeBorderData, pitchB));
2184 UInt layerSize = *Pointer<Int>(blit + OFFSET(CubeBorderData, layerSize));
2185 UInt dim = *Pointer<Int>(blit + OFFSET(CubeBorderData, dim));
2186
2187 // Low Border, Low Pixel, High Border, High Pixel
Ben Claytonfccfc562019-12-17 20:37:31 +00002188 Int LB(-1), LP(0), HB(dim), HP(dim - 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002189
2190 for(int face = 0; face < 6; face++)
2191 {
2192 computeCubeCorner(layers, LB, LP, LB, LP, pitchB, state);
2193 computeCubeCorner(layers, LB, LP, HB, HP, pitchB, state);
2194 computeCubeCorner(layers, HB, HP, LB, LP, pitchB, state);
2195 computeCubeCorner(layers, HB, HP, HB, HP, pitchB, state);
2196 layers = layers + layerSize;
2197 }
2198 }
2199
2200 return function("BlitRoutine");
2201}
2202
Alexis Hetu46159712020-06-15 16:13:51 -04002203void Blitter::updateBorders(vk::Image *image, const VkImageSubresource &subresource)
Nicolas Capens157ba262019-12-10 17:49:14 -05002204{
Alexis Hetu46159712020-06-15 16:13:51 -04002205 ASSERT(image->getArrayLayers() >= (subresource.arrayLayer + 6));
Nicolas Capens157ba262019-12-10 17:49:14 -05002206
2207 // From Vulkan 1.1 spec, section 11.5. Image Views:
2208 // "For cube and cube array image views, the layers of the image view starting
2209 // at baseArrayLayer correspond to faces in the order +X, -X, +Y, -Y, +Z, -Z."
Alexis Hetu46159712020-06-15 16:13:51 -04002210 VkImageSubresource posX = subresource;
2211 VkImageSubresource negX = posX;
2212 negX.arrayLayer++;
2213 VkImageSubresource posY = negX;
2214 posY.arrayLayer++;
2215 VkImageSubresource negY = posY;
2216 negY.arrayLayer++;
2217 VkImageSubresource posZ = negY;
2218 posZ.arrayLayer++;
2219 VkImageSubresource negZ = posZ;
2220 negZ.arrayLayer++;
Nicolas Capens157ba262019-12-10 17:49:14 -05002221
2222 // Copy top / bottom
2223 copyCubeEdge(image, posX, BOTTOM, negY, RIGHT);
2224 copyCubeEdge(image, posY, BOTTOM, posZ, TOP);
2225 copyCubeEdge(image, posZ, BOTTOM, negY, TOP);
2226 copyCubeEdge(image, negX, BOTTOM, negY, LEFT);
2227 copyCubeEdge(image, negY, BOTTOM, negZ, BOTTOM);
2228 copyCubeEdge(image, negZ, BOTTOM, negY, BOTTOM);
2229
2230 copyCubeEdge(image, posX, TOP, posY, RIGHT);
2231 copyCubeEdge(image, posY, TOP, negZ, TOP);
2232 copyCubeEdge(image, posZ, TOP, posY, BOTTOM);
2233 copyCubeEdge(image, negX, TOP, posY, LEFT);
2234 copyCubeEdge(image, negY, TOP, posZ, BOTTOM);
2235 copyCubeEdge(image, negZ, TOP, posY, TOP);
2236
2237 // Copy left / right
2238 copyCubeEdge(image, posX, RIGHT, negZ, LEFT);
2239 copyCubeEdge(image, posY, RIGHT, posX, TOP);
2240 copyCubeEdge(image, posZ, RIGHT, posX, LEFT);
2241 copyCubeEdge(image, negX, RIGHT, posZ, LEFT);
2242 copyCubeEdge(image, negY, RIGHT, posX, BOTTOM);
2243 copyCubeEdge(image, negZ, RIGHT, negX, LEFT);
2244
2245 copyCubeEdge(image, posX, LEFT, posZ, RIGHT);
2246 copyCubeEdge(image, posY, LEFT, negX, TOP);
2247 copyCubeEdge(image, posZ, LEFT, negX, RIGHT);
2248 copyCubeEdge(image, negX, LEFT, negZ, RIGHT);
2249 copyCubeEdge(image, negY, LEFT, negX, BOTTOM);
2250 copyCubeEdge(image, negZ, LEFT, posX, RIGHT);
2251
2252 // Compute corner colors
Alexis Hetu46159712020-06-15 16:13:51 -04002253 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
Nicolas Capens157ba262019-12-10 17:49:14 -05002254 vk::Format format = image->getFormat(aspect);
2255 VkSampleCountFlagBits samples = image->getSampleCountFlagBits();
2256 State state(format, format, samples, samples, Options{ 0xF });
2257
Nicolas Capensdd0e6002020-01-24 01:21:47 -05002258 // Vulkan 1.2: "If samples is not VK_SAMPLE_COUNT_1_BIT, then imageType must be
2259 // VK_IMAGE_TYPE_2D, flags must not contain VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT"
2260 ASSERT(samples == VK_SAMPLE_COUNT_1_BIT);
Nicolas Capens157ba262019-12-10 17:49:14 -05002261
2262 auto cornerUpdateRoutine = getCornerUpdateRoutine(state);
2263 if(!cornerUpdateRoutine)
2264 {
2265 return;
2266 }
2267
Alexis Hetu46159712020-06-15 16:13:51 -04002268 VkExtent3D extent = image->getMipLevelExtent(aspect, subresource.mipLevel);
Ben Claytonfccfc562019-12-17 20:37:31 +00002269 CubeBorderData data = {
Nicolas Capens157ba262019-12-10 17:49:14 -05002270 image->getTexelPointer({ 0, 0, 0 }, posX),
Alexis Hetu46159712020-06-15 16:13:51 -04002271 image->rowPitchBytes(aspect, subresource.mipLevel),
Nicolas Capens157ba262019-12-10 17:49:14 -05002272 static_cast<uint32_t>(image->getLayerSize(aspect)),
2273 extent.width
2274 };
2275 cornerUpdateRoutine(&data);
2276}
2277
Ben Claytonfccfc562019-12-17 20:37:31 +00002278void Blitter::copyCubeEdge(vk::Image *image,
Alexis Hetu46159712020-06-15 16:13:51 -04002279 const VkImageSubresource &dstSubresource, Edge dstEdge,
2280 const VkImageSubresource &srcSubresource, Edge srcEdge)
Nicolas Capens157ba262019-12-10 17:49:14 -05002281{
Alexis Hetu46159712020-06-15 16:13:51 -04002282 ASSERT(srcSubresource.aspectMask == dstSubresource.aspectMask);
2283 ASSERT(srcSubresource.mipLevel == dstSubresource.mipLevel);
2284 ASSERT(srcSubresource.arrayLayer != dstSubresource.arrayLayer);
Nicolas Capens157ba262019-12-10 17:49:14 -05002285
2286 // Figure out if the edges to be copied in reverse order respectively from one another
2287 // The copy should be reversed whenever the same edges are contiguous or if we're
2288 // copying top <-> right or bottom <-> left. This is explained by the layout, which is:
2289 //
2290 // | +y |
2291 // | -x | +z | +x | -z |
2292 // | -y |
2293
2294 bool reverse = (srcEdge == dstEdge) ||
2295 ((srcEdge == TOP) && (dstEdge == RIGHT)) ||
2296 ((srcEdge == RIGHT) && (dstEdge == TOP)) ||
2297 ((srcEdge == BOTTOM) && (dstEdge == LEFT)) ||
2298 ((srcEdge == LEFT) && (dstEdge == BOTTOM));
2299
Alexis Hetu46159712020-06-15 16:13:51 -04002300 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(srcSubresource.aspectMask);
Nicolas Capens157ba262019-12-10 17:49:14 -05002301 int bytes = image->getFormat(aspect).bytes();
Alexis Hetu46159712020-06-15 16:13:51 -04002302 int pitchB = image->rowPitchBytes(aspect, srcSubresource.mipLevel);
Nicolas Capens157ba262019-12-10 17:49:14 -05002303
Alexis Hetu46159712020-06-15 16:13:51 -04002304 VkExtent3D extent = image->getMipLevelExtent(aspect, srcSubresource.mipLevel);
Nicolas Capens157ba262019-12-10 17:49:14 -05002305 int w = extent.width;
2306 int h = extent.height;
2307 if(w != h)
2308 {
2309 UNSUPPORTED("Cube doesn't have square faces : (%d, %d)", w, h);
2310 }
2311
2312 // Src is expressed in the regular [0, width-1], [0, height-1] space
2313 bool srcHorizontal = ((srcEdge == TOP) || (srcEdge == BOTTOM));
2314 int srcDelta = srcHorizontal ? bytes : pitchB;
2315 VkOffset3D srcOffset = { (srcEdge == RIGHT) ? (w - 1) : 0, (srcEdge == BOTTOM) ? (h - 1) : 0, 0 };
2316
2317 // Dst contains borders, so it is expressed in the [-1, width], [-1, height] space
2318 bool dstHorizontal = ((dstEdge == TOP) || (dstEdge == BOTTOM));
2319 int dstDelta = (dstHorizontal ? bytes : pitchB) * (reverse ? -1 : 1);
2320 VkOffset3D dstOffset = { (dstEdge == RIGHT) ? w : -1, (dstEdge == BOTTOM) ? h : -1, 0 };
2321
2322 // Don't write in the corners
2323 if(dstHorizontal)
2324 {
2325 dstOffset.x += reverse ? w : 1;
2326 }
2327 else
2328 {
2329 dstOffset.y += reverse ? h : 1;
2330 }
2331
Alexis Hetu46159712020-06-15 16:13:51 -04002332 const uint8_t *src = static_cast<const uint8_t *>(image->getTexelPointer(srcOffset, srcSubresource));
2333 uint8_t *dst = static_cast<uint8_t *>(image->getTexelPointer(dstOffset, dstSubresource));
Nicolas Capens157ba262019-12-10 17:49:14 -05002334 ASSERT((src < image->end()) && ((src + (w * srcDelta)) < image->end()));
2335 ASSERT((dst < image->end()) && ((dst + (w * dstDelta)) < image->end()));
2336
2337 for(int i = 0; i < w; ++i, dst += dstDelta, src += srcDelta)
2338 {
2339 memcpy(dst, src, bytes);
2340 }
2341}
2342
Ben Claytonfccfc562019-12-17 20:37:31 +00002343} // namespace sw