[WASAPI] fix stream types and frequencies enumeration
[xbmc.git] / xbmc / guilib / Texture.cpp
blobb59e3588e55e7266272f1c47707873036b37df85
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 "Texture.h"
11 #include "DDSImage.h"
12 #include "ServiceBroker.h"
13 #include "URL.h"
14 #include "commons/ilog.h"
15 #include "filesystem/File.h"
16 #include "filesystem/ResourceFile.h"
17 #include "filesystem/XbtFile.h"
18 #include "guilib/TextureBase.h"
19 #include "guilib/TextureFormats.h"
20 #include "guilib/iimage.h"
21 #include "guilib/imagefactory.h"
22 #include "messaging/ApplicationMessenger.h"
23 #include "utils/URIUtils.h"
24 #include "utils/log.h"
25 #include "windowing/WinSystem.h"
26 #if defined(TARGET_DARWIN_EMBEDDED)
27 #include <ImageIO/ImageIO.h>
28 #include "filesystem/File.h"
29 #endif
30 #if defined(TARGET_ANDROID)
31 #include "platform/android/filesystem/AndroidAppFile.h"
32 #endif
33 #include "rendering/RenderSystem.h"
34 #include "utils/MemUtils.h"
36 #include <algorithm>
37 #include <cstring>
38 #include <exception>
39 #include <utility>
41 /************************************************************************/
42 /* */
43 /************************************************************************/
44 CTexture::CTexture(unsigned int width, unsigned int height, XB_FMT format)
46 m_pixels = NULL;
47 m_loadedToGPU = false;
48 Allocate(width, height, format);
51 CTexture::~CTexture()
53 KODI::MEMORY::AlignedFree(m_pixels);
54 m_pixels = NULL;
57 void CTexture::Update(unsigned int width,
58 unsigned int height,
59 unsigned int pitch,
60 XB_FMT format,
61 const unsigned char* pixels,
62 bool loadToGPU)
64 if (pixels == NULL)
65 return;
67 if (format & XB_FMT_DXT_MASK)
68 return;
70 Allocate(width, height, format);
72 if (m_pixels == nullptr)
73 return;
75 unsigned int srcPitch = pitch ? pitch : GetPitch(width);
76 unsigned int srcRows = GetRows(height);
77 unsigned int dstPitch = GetPitch(m_textureWidth);
78 unsigned int dstRows = GetRows(m_textureHeight);
80 if (srcPitch == dstPitch)
81 memcpy(m_pixels, pixels, srcPitch * std::min(srcRows, dstRows));
82 else
84 const unsigned char *src = pixels;
85 unsigned char* dst = m_pixels;
86 for (unsigned int y = 0; y < srcRows && y < dstRows; y++)
88 memcpy(dst, src, std::min(srcPitch, dstPitch));
89 src += srcPitch;
90 dst += dstPitch;
93 ClampToEdge();
95 if (loadToGPU)
96 LoadToGPU();
99 std::unique_ptr<CTexture> CTexture::LoadFromFile(const std::string& texturePath,
100 unsigned int idealWidth,
101 unsigned int idealHeight,
102 bool requirePixels,
103 const std::string& strMimeType)
105 #if defined(TARGET_ANDROID)
106 CURL url(texturePath);
107 if (url.IsProtocol("androidapp"))
109 XFILE::CFileAndroidApp file;
110 if (file.Open(url))
112 unsigned char* inputBuff;
113 unsigned int width;
114 unsigned int height;
115 unsigned int inputBuffSize = file.ReadIcon(&inputBuff, &width, &height);
116 file.Close();
117 if (!inputBuffSize)
118 return NULL;
120 std::unique_ptr<CTexture> texture = CTexture::CreateTexture();
121 texture->LoadFromMemory(width, height, width*4, XB_FMT_RGBA8, true, inputBuff);
122 delete[] inputBuff;
123 return texture;
126 #endif
127 std::unique_ptr<CTexture> texture = CTexture::CreateTexture();
128 if (texture->LoadFromFileInternal(texturePath, idealWidth, idealHeight, requirePixels, strMimeType))
129 return texture;
130 return {};
133 std::unique_ptr<CTexture> CTexture::LoadFromFileInMemory(unsigned char* buffer,
134 size_t bufferSize,
135 const std::string& mimeType,
136 unsigned int idealWidth,
137 unsigned int idealHeight)
139 std::unique_ptr<CTexture> texture = CTexture::CreateTexture();
140 if (texture->LoadFromFileInMem(buffer, bufferSize, mimeType, idealWidth, idealHeight))
141 return texture;
142 return {};
145 bool CTexture::LoadFromFileInternal(const std::string& texturePath,
146 unsigned int maxWidth,
147 unsigned int maxHeight,
148 bool requirePixels,
149 const std::string& strMimeType)
151 if (URIUtils::HasExtension(texturePath, ".dds"))
152 { // special case for DDS images
153 CDDSImage image;
154 if (image.ReadFile(texturePath))
156 Update(image.GetWidth(), image.GetHeight(), 0, image.GetFormat(), image.GetData(), false);
157 return true;
159 return false;
162 unsigned int width = maxWidth ? std::min(maxWidth, CServiceBroker::GetRenderSystem()->GetMaxTextureSize()) :
163 CServiceBroker::GetRenderSystem()->GetMaxTextureSize();
164 unsigned int height = maxHeight ? std::min(maxHeight, CServiceBroker::GetRenderSystem()->GetMaxTextureSize()) :
165 CServiceBroker::GetRenderSystem()->GetMaxTextureSize();
167 // Read image into memory to use our vfs
168 XFILE::CFile file;
169 std::vector<uint8_t> buf;
171 if (file.LoadFile(texturePath, buf) <= 0)
172 return false;
174 CURL url(texturePath);
175 // make sure resource:// paths are properly resolved
176 if (url.IsProtocol("resource"))
178 std::string translatedPath;
179 if (XFILE::CResourceFile::TranslatePath(url, translatedPath))
180 url.Parse(translatedPath);
183 // handle xbt:// paths differently because it allows loading the texture directly from memory
184 if (url.IsProtocol("xbt"))
186 XFILE::CXbtFile xbtFile;
187 if (!xbtFile.Open(url))
188 return false;
189 if (xbtFile.GetKDFormatType())
191 return UploadFromMemory(xbtFile.GetImageWidth(), xbtFile.GetImageHeight(), 0, buf.data(),
192 xbtFile.GetKDFormat(), xbtFile.GetKDAlpha(), xbtFile.GetKDSwizzle());
194 else if (xbtFile.GetImageFormat() == XB_FMT_A8R8G8B8)
196 KD_TEX_ALPHA alpha = xbtFile.HasImageAlpha() ? KD_TEX_ALPHA_STRAIGHT : KD_TEX_ALPHA_OPAQUE;
197 return UploadFromMemory(xbtFile.GetImageWidth(), xbtFile.GetImageHeight(), 0, buf.data(),
198 KD_TEX_FMT_SDR_BGRA8, alpha, KD_TEX_SWIZ_RGBA);
200 else
202 return false;
206 IImage* pImage;
208 if(strMimeType.empty())
209 pImage = ImageFactory::CreateLoader(texturePath);
210 else
211 pImage = ImageFactory::CreateLoaderFromMimeType(strMimeType);
213 if (!LoadIImage(pImage, buf.data(), buf.size(), width, height))
215 CLog::Log(LOGDEBUG, "{} - Load of {} failed.", __FUNCTION__, CURL::GetRedacted(texturePath));
216 delete pImage;
217 return false;
219 delete pImage;
221 return true;
224 bool CTexture::LoadFromFileInMem(unsigned char* buffer,
225 size_t size,
226 const std::string& mimeType,
227 unsigned int maxWidth,
228 unsigned int maxHeight)
230 if (!buffer || !size)
231 return false;
233 unsigned int width = maxWidth ? std::min(maxWidth, CServiceBroker::GetRenderSystem()->GetMaxTextureSize()) :
234 CServiceBroker::GetRenderSystem()->GetMaxTextureSize();
235 unsigned int height = maxHeight ? std::min(maxHeight, CServiceBroker::GetRenderSystem()->GetMaxTextureSize()) :
236 CServiceBroker::GetRenderSystem()->GetMaxTextureSize();
238 IImage* pImage = ImageFactory::CreateLoaderFromMimeType(mimeType);
239 if(!LoadIImage(pImage, buffer, size, width, height))
241 delete pImage;
242 return false;
244 delete pImage;
245 return true;
248 bool CTexture::LoadIImage(IImage* pImage,
249 unsigned char* buffer,
250 unsigned int bufSize,
251 unsigned int width,
252 unsigned int height)
254 if (pImage == nullptr)
255 return false;
257 if (!pImage->LoadImageFromMemory(buffer, bufSize, width, height))
258 return false;
260 if (pImage->Width() == 0 || pImage->Height() == 0)
261 return false;
263 // align all textures so that they have an even width
264 // in some circumstances when we downsize a thumbnail
265 // which has an uneven number of pixels in width
266 // we crash in CPicture::ScaleImage in ffmpegs swscale
267 // because it tries to access beyond the source memory
268 // (happens on osx and ios)
269 // UPDATE: don't just update to be on an even width;
270 // ffmpegs swscale relies on a 16-byte stride on some systems
271 // so the textureWidth needs to be a multiple of 16. see ffmpeg
272 // swscale headers for more info.
273 unsigned int textureWidth = ((pImage->Width() + 15) / 16) * 16;
275 Allocate(textureWidth, pImage->Height(), XB_FMT_A8R8G8B8);
277 m_imageWidth = std::min(m_imageWidth, textureWidth);
279 if (m_pixels == nullptr)
280 return false;
282 if (!pImage->Decode(m_pixels, GetTextureWidth(), GetRows(), GetPitch(), XB_FMT_A8R8G8B8))
283 return false;
285 if (pImage->Orientation())
286 m_orientation = pImage->Orientation() - 1;
288 m_textureAlpha = pImage->hasAlpha() ? KD_TEX_ALPHA_STRAIGHT : KD_TEX_ALPHA_OPAQUE;
289 m_originalWidth = pImage->originalWidth();
290 m_originalHeight = pImage->originalHeight();
291 m_imageWidth = pImage->Width();
292 m_imageHeight = pImage->Height();
294 ClampToEdge();
296 return true;
299 void CTexture::LoadToGPUAsync()
301 // Already in main context?
302 if (CServiceBroker::GetWinSystem()->HasContext())
303 return;
305 if (!CServiceBroker::GetWinSystem()->BindTextureUploadContext())
306 return;
308 LoadToGPU();
310 SyncGPU();
312 CServiceBroker::GetWinSystem()->UnbindTextureUploadContext();
315 bool CTexture::LoadFromMemory(unsigned int width,
316 unsigned int height,
317 unsigned int pitch,
318 XB_FMT format,
319 bool hasAlpha,
320 const unsigned char* pixels)
322 m_imageWidth = m_originalWidth = width;
323 m_imageHeight = m_originalHeight = height;
324 m_format = format;
325 m_textureAlpha = hasAlpha ? KD_TEX_ALPHA_STRAIGHT : KD_TEX_ALPHA_OPAQUE;
326 Update(width, height, pitch, format, pixels, false);
327 return true;
330 bool CTexture::UploadFromMemory(unsigned int width,
331 unsigned int height,
332 unsigned int pitch,
333 unsigned char* pixels,
334 KD_TEX_FMT format,
335 KD_TEX_ALPHA alpha,
336 KD_TEX_SWIZ swizzle)
338 m_imageWidth = m_textureWidth = m_originalWidth = width;
339 m_imageHeight = m_textureHeight = m_originalHeight = height;
340 m_textureFormat = format;
341 m_textureAlpha = alpha;
342 m_textureSwizzle = swizzle;
344 if (!SupportsFormat(m_textureFormat, m_textureSwizzle) && !ConvertToLegacy(width, height, pixels))
346 CLog::LogF(
347 LOGERROR,
348 "Failed to upload texture. Format {} and swizzle {} not supported by the texture pipeline.",
349 m_textureFormat, m_textureSwizzle);
351 m_loadedToGPU = true;
352 return false;
355 if (CServiceBroker::GetAppMessenger()->IsProcessThread())
357 if (m_pixels)
359 LoadToGPU();
361 else
363 // just a borrowed buffer
364 m_pixels = pixels;
365 m_bCacheMemory = true;
366 LoadToGPU();
367 m_bCacheMemory = false;
368 m_pixels = nullptr;
371 else if (!m_pixels)
373 size_t size = GetPitch() * GetRows();
374 m_pixels = static_cast<unsigned char*>(KODI::MEMORY::AlignedMalloc(size, 32));
375 if (m_pixels == nullptr)
377 CLog::LogF(LOGERROR, "Could not allocate {} bytes. Out of memory.", size);
378 return false;
380 std::memcpy(m_pixels, pixels, size);
383 return true;
386 bool CTexture::LoadPaletted(unsigned int width,
387 unsigned int height,
388 unsigned int pitch,
389 XB_FMT format,
390 const unsigned char* pixels,
391 const COLOR* palette)
393 if (pixels == NULL || palette == NULL)
394 return false;
396 Allocate(width, height, format);
398 for (unsigned int y = 0; y < m_imageHeight; y++)
400 unsigned char *dest = m_pixels + y * GetPitch();
401 const unsigned char *src = pixels + y * pitch;
402 for (unsigned int x = 0; x < m_imageWidth; x++)
404 COLOR col = palette[*src++];
405 *dest++ = col.b;
406 *dest++ = col.g;
407 *dest++ = col.r;
408 *dest++ = col.x;
411 ClampToEdge();
412 return true;