[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / guilib / TextureBase.cpp
blob5c2c01e22b35944f6e01a26c9c4cdb15fc9cb595
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "TextureBase.h"
11 #include "ServiceBroker.h"
12 #include "commons/ilog.h"
13 #include "guilib/TextureFormats.h"
14 #include "rendering/RenderSystem.h"
15 #include "utils/MemUtils.h"
16 #include "utils/log.h"
18 #include <algorithm>
19 #include <cstdint>
20 #include <cstring>
21 #include <exception>
22 #include <utility>
24 void CTextureBase::Allocate(uint32_t width, uint32_t height, XB_FMT format)
26 SetKDFormat(format);
27 m_imageWidth = m_originalWidth = width;
28 m_imageHeight = m_originalHeight = height;
29 m_format = format;
30 m_orientation = 0;
32 m_textureWidth = m_imageWidth;
33 m_textureHeight = m_imageHeight;
35 if (!CServiceBroker::GetRenderSystem()->SupportsNPOT((m_textureFormat & KD_TEX_FMT_TYPE_MASK) !=
36 KD_TEX_FMT_S3TC))
38 m_textureWidth = PadPow2(m_textureWidth);
39 m_textureHeight = PadPow2(m_textureHeight);
42 if ((m_textureFormat & KD_TEX_FMT_TYPE_MASK) == KD_TEX_FMT_S3TC)
44 // DXT textures must be a multiple of 4 in width and height
45 m_textureWidth = ((m_textureWidth + 3) / 4) * 4;
46 m_textureHeight = ((m_textureHeight + 3) / 4) * 4;
48 else
50 // align all textures so that they have an even width
51 // in some circumstances when we downsize a thumbnail
52 // which has an uneven number of pixels in width
53 // we crash in CPicture::ScaleImage in ffmpegs swscale
54 // because it tries to access beyond the source memory
55 // (happens on osx and ios)
56 // UPDATE: don't just update to be on an even width;
57 // ffmpegs swscale relies on a 16-byte stride on some systems
58 // so the textureWidth needs to be a multiple of 16. see ffmpeg
59 // swscale headers for more info.
60 m_textureWidth = ((m_textureWidth + 15) / 16) * 16;
63 // check for max texture size
64 m_textureWidth = std::min(m_textureWidth, CServiceBroker::GetRenderSystem()->GetMaxTextureSize());
65 m_textureHeight =
66 std::min(m_textureHeight, CServiceBroker::GetRenderSystem()->GetMaxTextureSize());
67 m_imageWidth = std::min(m_imageWidth, m_textureWidth);
68 m_imageHeight = std::min(m_imageHeight, m_textureHeight);
70 KODI::MEMORY::AlignedFree(m_pixels);
71 m_pixels = NULL;
73 size_t size = GetPitch() * GetRows();
75 if (size == 0)
76 return;
78 m_pixels = static_cast<unsigned char*>(KODI::MEMORY::AlignedMalloc(size, 32));
80 if (m_pixels == nullptr)
81 CLog::Log(LOGERROR, "{} - Could not allocate {} bytes. Out of memory.", __FUNCTION__, size);
84 uint32_t CTextureBase::PadPow2(uint32_t x)
86 --x;
87 x |= x >> 1;
88 x |= x >> 2;
89 x |= x >> 4;
90 x |= x >> 8;
91 x |= x >> 16;
92 return ++x;
95 bool CTextureBase::SwapBlueRed(
96 uint8_t* pixels, uint32_t height, uint32_t pitch, uint32_t elements, uint32_t offset)
98 if (!pixels)
99 return false;
100 uint8_t* dst = pixels;
101 for (uint32_t y = 0; y < height; y++)
103 dst = pixels + (y * pitch);
104 for (uint32_t x = 0; x < pitch; x += elements)
105 std::swap(dst[x + offset], dst[x + 2 + offset]);
107 return true;
110 void CTextureBase::ClampToEdge()
112 if (m_pixels == nullptr)
113 return;
115 uint32_t imagePitch = GetPitch(m_imageWidth);
116 uint32_t imageRows = GetRows(m_imageHeight);
117 uint32_t texturePitch = GetPitch(m_textureWidth);
118 uint32_t textureRows = GetRows(m_textureHeight);
120 if (imagePitch < texturePitch)
122 uint32_t blockSize = GetBlockSize();
123 unsigned char* src = m_pixels + imagePitch - blockSize;
124 unsigned char* dst = m_pixels;
125 for (uint32_t y = 0; y < imageRows; y++)
127 for (uint32_t x = imagePitch; x < texturePitch; x += blockSize)
128 memcpy(dst + x, src, blockSize);
129 dst += texturePitch;
133 if (imageRows < textureRows)
135 unsigned char* dst = m_pixels + imageRows * texturePitch;
136 for (uint32_t y = imageRows; y < textureRows; y++)
138 memcpy(dst, dst - texturePitch, texturePitch);
139 dst += texturePitch;
144 uint32_t CTextureBase::GetPitch(uint32_t width) const
146 uint32_t blockWidth = GetBlockWidth();
147 uint32_t pitch = ((width + blockWidth - 1) / blockWidth) * GetBlockSize();
149 // For the GPU, RGB8 needs to be aligned to 32 bit
150 if (m_textureFormat == KD_TEX_FMT_SDR_RGB8)
151 pitch = ((pitch + 3) / 4) * 4;
153 return pitch;
156 uint32_t CTextureBase::GetRows(uint32_t height) const
158 uint32_t blockHeight = GetBlockHeight();
159 return (height + blockHeight - 1) / blockHeight;
162 uint32_t CTextureBase::GetBlockWidth() const
164 switch (m_textureFormat)
166 case KD_TEX_FMT_SDR_R8:
167 case KD_TEX_FMT_SDR_RG8:
168 case KD_TEX_FMT_SDR_R5G6B5:
169 case KD_TEX_FMT_SDR_RGB5_A1:
170 case KD_TEX_FMT_SDR_RGBA4:
171 case KD_TEX_FMT_SDR_RGB8:
172 case KD_TEX_FMT_SDR_RGBA8:
173 case KD_TEX_FMT_SDR_BGRA8:
174 case KD_TEX_FMT_HDR_R16f:
175 case KD_TEX_FMT_HDR_RG16f:
176 case KD_TEX_FMT_HDR_R11F_G11F_B10F:
177 case KD_TEX_FMT_HDR_RGB9_E5:
178 case KD_TEX_FMT_HDR_RGB10_A2:
179 case KD_TEX_FMT_HDR_RGBA16f:
180 return 1;
181 case KD_TEX_FMT_YUV_YUYV8:
182 return 2;
183 case KD_TEX_FMT_S3TC_RGB8:
184 case KD_TEX_FMT_S3TC_RGB8_A1:
185 case KD_TEX_FMT_S3TC_RGB8_A4:
186 case KD_TEX_FMT_S3TC_RGBA8:
187 case KD_TEX_FMT_RGTC_R11:
188 case KD_TEX_FMT_RGTC_RG11:
189 case KD_TEX_FMT_BPTC_RGB16F:
190 case KD_TEX_FMT_BPTC_RGBA8:
191 case KD_TEX_FMT_ETC1:
192 case KD_TEX_FMT_ETC2_RGB8:
193 case KD_TEX_FMT_ETC2_RGB8_A1:
194 case KD_TEX_FMT_ETC2_RGBA8:
195 case KD_TEX_FMT_ETC2_R11:
196 case KD_TEX_FMT_ETC2_RG11:
197 case KD_TEX_FMT_ASTC_LDR_4x4:
198 case KD_TEX_FMT_ASTC_HDR_4x4:
199 return 4;
200 case KD_TEX_FMT_ASTC_LDR_5x4:
201 case KD_TEX_FMT_ASTC_LDR_5x5:
202 case KD_TEX_FMT_ASTC_HDR_5x4:
203 case KD_TEX_FMT_ASTC_HDR_5x5:
204 return 5;
205 case KD_TEX_FMT_ASTC_LDR_6x5:
206 case KD_TEX_FMT_ASTC_LDR_6x6:
207 case KD_TEX_FMT_ASTC_HDR_6x5:
208 case KD_TEX_FMT_ASTC_HDR_6x6:
209 return 6;
210 case KD_TEX_FMT_ASTC_LDR_8x5:
211 case KD_TEX_FMT_ASTC_LDR_8x6:
212 case KD_TEX_FMT_ASTC_LDR_8x8:
213 case KD_TEX_FMT_ASTC_HDR_8x5:
214 case KD_TEX_FMT_ASTC_HDR_8x6:
215 case KD_TEX_FMT_ASTC_HDR_8x8:
216 return 8;
217 case KD_TEX_FMT_ASTC_LDR_10x5:
218 case KD_TEX_FMT_ASTC_LDR_10x6:
219 case KD_TEX_FMT_ASTC_LDR_10x8:
220 case KD_TEX_FMT_ASTC_LDR_10x10:
221 case KD_TEX_FMT_ASTC_HDR_10x5:
222 case KD_TEX_FMT_ASTC_HDR_10x6:
223 case KD_TEX_FMT_ASTC_HDR_10x8:
224 case KD_TEX_FMT_ASTC_HDR_10x10:
225 return 10;
226 case KD_TEX_FMT_ASTC_LDR_12x10:
227 case KD_TEX_FMT_ASTC_LDR_12x12:
228 case KD_TEX_FMT_ASTC_HDR_12x10:
229 case KD_TEX_FMT_ASTC_HDR_12x12:
230 return 12;
231 default:
232 return 1;
236 uint32_t CTextureBase::GetBlockHeight() const
238 switch (m_textureFormat)
240 case KD_TEX_FMT_SDR_R8:
241 case KD_TEX_FMT_SDR_RG8:
242 case KD_TEX_FMT_SDR_R5G6B5:
243 case KD_TEX_FMT_SDR_RGB5_A1:
244 case KD_TEX_FMT_SDR_RGBA4:
245 case KD_TEX_FMT_SDR_RGB8:
246 case KD_TEX_FMT_SDR_RGBA8:
247 case KD_TEX_FMT_SDR_BGRA8:
248 case KD_TEX_FMT_HDR_R16f:
249 case KD_TEX_FMT_HDR_RG16f:
250 case KD_TEX_FMT_HDR_R11F_G11F_B10F:
251 case KD_TEX_FMT_HDR_RGB9_E5:
252 case KD_TEX_FMT_HDR_RGB10_A2:
253 case KD_TEX_FMT_HDR_RGBA16f:
254 case KD_TEX_FMT_YUV_YUYV8:
255 return 1;
256 case KD_TEX_FMT_S3TC_RGB8:
257 case KD_TEX_FMT_S3TC_RGB8_A1:
258 case KD_TEX_FMT_S3TC_RGB8_A4:
259 case KD_TEX_FMT_S3TC_RGBA8:
260 case KD_TEX_FMT_RGTC_R11:
261 case KD_TEX_FMT_RGTC_RG11:
262 case KD_TEX_FMT_BPTC_RGB16F:
263 case KD_TEX_FMT_BPTC_RGBA8:
264 case KD_TEX_FMT_ETC1:
265 case KD_TEX_FMT_ETC2_RGB8:
266 case KD_TEX_FMT_ETC2_RGB8_A1:
267 case KD_TEX_FMT_ETC2_RGBA8:
268 case KD_TEX_FMT_ETC2_R11:
269 case KD_TEX_FMT_ETC2_RG11:
270 case KD_TEX_FMT_ASTC_LDR_4x4:
271 case KD_TEX_FMT_ASTC_LDR_5x4:
272 case KD_TEX_FMT_ASTC_HDR_4x4:
273 case KD_TEX_FMT_ASTC_HDR_5x4:
274 return 4;
275 case KD_TEX_FMT_ASTC_LDR_5x5:
276 case KD_TEX_FMT_ASTC_LDR_6x5:
277 case KD_TEX_FMT_ASTC_LDR_8x5:
278 case KD_TEX_FMT_ASTC_LDR_10x5:
279 case KD_TEX_FMT_ASTC_HDR_5x5:
280 case KD_TEX_FMT_ASTC_HDR_6x5:
281 case KD_TEX_FMT_ASTC_HDR_8x5:
282 case KD_TEX_FMT_ASTC_HDR_10x5:
283 return 5;
284 case KD_TEX_FMT_ASTC_LDR_6x6:
285 case KD_TEX_FMT_ASTC_LDR_8x6:
286 case KD_TEX_FMT_ASTC_LDR_10x6:
287 case KD_TEX_FMT_ASTC_HDR_6x6:
288 case KD_TEX_FMT_ASTC_HDR_8x6:
289 case KD_TEX_FMT_ASTC_HDR_10x6:
290 return 6;
291 case KD_TEX_FMT_ASTC_LDR_8x8:
292 case KD_TEX_FMT_ASTC_LDR_10x8:
293 case KD_TEX_FMT_ASTC_HDR_8x8:
294 case KD_TEX_FMT_ASTC_HDR_10x8:
295 return 8;
296 case KD_TEX_FMT_ASTC_LDR_10x10:
297 case KD_TEX_FMT_ASTC_LDR_12x10:
298 case KD_TEX_FMT_ASTC_HDR_10x10:
299 case KD_TEX_FMT_ASTC_HDR_12x10:
300 return 10;
301 case KD_TEX_FMT_ASTC_LDR_12x12:
302 case KD_TEX_FMT_ASTC_HDR_12x12:
303 return 12;
304 default:
305 return 4;
309 uint32_t CTextureBase::GetBlockSize() const
311 switch (m_textureFormat)
313 case KD_TEX_FMT_SDR_R8:
314 return 1;
315 case KD_TEX_FMT_SDR_RG8:
316 case KD_TEX_FMT_SDR_R5G6B5:
317 case KD_TEX_FMT_SDR_RGB5_A1:
318 case KD_TEX_FMT_SDR_RGBA4:
319 case KD_TEX_FMT_HDR_R16f:
320 return 2;
321 case KD_TEX_FMT_SDR_RGB8:
322 return 3;
323 case KD_TEX_FMT_SDR_RGBA8:
324 case KD_TEX_FMT_SDR_BGRA8:
325 case KD_TEX_FMT_HDR_RG16f:
326 case KD_TEX_FMT_HDR_R11F_G11F_B10F:
327 case KD_TEX_FMT_HDR_RGB9_E5:
328 case KD_TEX_FMT_HDR_RGB10_A2:
329 case KD_TEX_FMT_YUV_YUYV8:
330 return 4;
331 case KD_TEX_FMT_HDR_RGBA16f:
332 case KD_TEX_FMT_S3TC_RGB8:
333 case KD_TEX_FMT_S3TC_RGB8_A1:
334 case KD_TEX_FMT_RGTC_R11:
335 case KD_TEX_FMT_ETC1:
336 case KD_TEX_FMT_ETC2_RGB8:
337 case KD_TEX_FMT_ETC2_RGB8_A1:
338 case KD_TEX_FMT_ETC2_R11:
339 return 8;
340 case KD_TEX_FMT_S3TC_RGB8_A4:
341 case KD_TEX_FMT_S3TC_RGBA8:
342 case KD_TEX_FMT_RGTC_RG11:
343 case KD_TEX_FMT_BPTC_RGB16F:
344 case KD_TEX_FMT_BPTC_RGBA8:
345 case KD_TEX_FMT_ETC2_RG11:
346 case KD_TEX_FMT_ETC2_RGBA8:
347 case KD_TEX_FMT_ASTC_LDR_4x4:
348 case KD_TEX_FMT_ASTC_LDR_5x4:
349 case KD_TEX_FMT_ASTC_LDR_5x5:
350 case KD_TEX_FMT_ASTC_LDR_6x5:
351 case KD_TEX_FMT_ASTC_LDR_6x6:
352 case KD_TEX_FMT_ASTC_LDR_8x5:
353 case KD_TEX_FMT_ASTC_LDR_8x6:
354 case KD_TEX_FMT_ASTC_LDR_8x8:
355 case KD_TEX_FMT_ASTC_LDR_10x5:
356 case KD_TEX_FMT_ASTC_LDR_10x6:
357 case KD_TEX_FMT_ASTC_LDR_10x8:
358 case KD_TEX_FMT_ASTC_LDR_10x10:
359 case KD_TEX_FMT_ASTC_LDR_12x10:
360 case KD_TEX_FMT_ASTC_LDR_12x12:
361 case KD_TEX_FMT_ASTC_HDR_4x4:
362 case KD_TEX_FMT_ASTC_HDR_5x4:
363 case KD_TEX_FMT_ASTC_HDR_5x5:
364 case KD_TEX_FMT_ASTC_HDR_6x5:
365 case KD_TEX_FMT_ASTC_HDR_6x6:
366 case KD_TEX_FMT_ASTC_HDR_8x5:
367 case KD_TEX_FMT_ASTC_HDR_8x6:
368 case KD_TEX_FMT_ASTC_HDR_8x8:
369 case KD_TEX_FMT_ASTC_HDR_10x5:
370 case KD_TEX_FMT_ASTC_HDR_10x6:
371 case KD_TEX_FMT_ASTC_HDR_10x8:
372 case KD_TEX_FMT_ASTC_HDR_10x10:
373 case KD_TEX_FMT_ASTC_HDR_12x10:
374 case KD_TEX_FMT_ASTC_HDR_12x12:
375 return 16;
376 default:
377 return 4;
381 void CTextureBase::SetKDFormat(XB_FMT xbFMT)
383 switch (xbFMT)
385 case XB_FMT_DXT1:
386 m_textureFormat = KD_TEX_FMT_S3TC_RGB8;
387 return;
388 case XB_FMT_DXT3:
389 m_textureFormat = KD_TEX_FMT_S3TC_RGB8_A4;
390 return;
391 case XB_FMT_DXT5:
392 m_textureFormat = KD_TEX_FMT_S3TC_RGBA8;
393 return;
394 case XB_FMT_A8R8G8B8:
395 m_textureFormat = KD_TEX_FMT_SDR_BGRA8;
396 return;
397 case XB_FMT_A8:
398 m_textureFormat = KD_TEX_FMT_SDR_R8;
399 m_textureSwizzle = KD_TEX_SWIZ_111R;
400 return;
401 case XB_FMT_RGBA8:
402 m_textureFormat = KD_TEX_FMT_SDR_RGBA8;
403 return;
404 case XB_FMT_RGB8:
405 m_textureFormat = KD_TEX_FMT_SDR_RGB8;
406 return;
407 case XB_FMT_UNKNOWN:
408 case XB_FMT_DXT5_YCoCg:
409 default:
410 m_textureFormat = KD_TEX_FMT_UNKNOWN;
411 return;