void CDXTexture::LoadToGPU() { if (!m_pixels) { // nothing to load - probably same image (no change) return; } bool needUpdate = true; D3D11_USAGE usage = D3D11_USAGE_DEFAULT; if (m_format == XB_FMT_RGB8) usage = D3D11_USAGE_DYNAMIC; // fallback to dynamic to allow CPU write to texture if (m_texture.Get() == nullptr) { // creates texture with initial data if (m_format != XB_FMT_RGB8) { // this is faster way to create texture with initial data instead of create empty and then copy to it m_texture.Create(m_textureWidth, m_textureHeight, IsMipmapped() ? 0 : 1, usage, GetFormat(), m_pixels, GetPitch()); if (m_texture.Get() != nullptr) needUpdate = false; } else m_texture.Create(m_textureWidth, m_textureHeight, IsMipmapped() ? 0 : 1, usage, GetFormat()); if (m_texture.Get() == nullptr) { CLog::Log(LOGDEBUG, "CDXTexture::CDXTexture: Error creating new texture for size %d x %d.", m_textureWidth, m_textureHeight); return; } } else { // need to update texture, check usage first D3D11_TEXTURE2D_DESC texDesc; m_texture.GetDesc(&texDesc); usage = texDesc.Usage; // if usage is not dynamic re-create texture with dynamic usage for future updates if (usage != D3D11_USAGE_DYNAMIC && usage != D3D11_USAGE_STAGING) { m_texture.Release(); usage = D3D11_USAGE_DYNAMIC; m_texture.Create(m_textureWidth, m_textureHeight, IsMipmapped() ? 0 : 1, usage, GetFormat(), m_pixels, GetPitch()); if (m_texture.Get() == nullptr) { CLog::Log(LOGDEBUG, "CDXTexture::CDXTexture: Error creating new texture for size %d x %d.", m_textureWidth, m_textureHeight); return; } needUpdate = false; } } if (needUpdate) { D3D11_MAP mapType = (usage == D3D11_USAGE_STAGING) ? D3D11_MAP_WRITE : D3D11_MAP_WRITE_DISCARD; D3D11_MAPPED_SUBRESOURCE lr; if (m_texture.LockRect(0, &lr, mapType)) { unsigned char *dst = (unsigned char *)lr.pData; unsigned char *src = m_pixels; unsigned int dstPitch = lr.RowPitch; unsigned int srcPitch = GetPitch(); unsigned int minPitch = std::min(srcPitch, dstPitch); unsigned int rows = GetRows(); if (m_format == XB_FMT_RGB8) { for (unsigned int y = 0; y < rows; y++) { unsigned char *dst2 = dst; unsigned char *src2 = src; for (unsigned int x = 0; x < srcPitch / 3; x++, dst2 += 4, src2 += 3) { dst2[0] = src2[2]; dst2[1] = src2[1]; dst2[2] = src2[0]; dst2[3] = 0xff; } src += srcPitch; dst += dstPitch; } } else if (srcPitch == dstPitch) { memcpy(dst, src, srcPitch * rows); } else { for (unsigned int y = 0; y < rows; y++) { memcpy(dst, src, minPitch); src += srcPitch; dst += dstPitch; } } } else { CLog::Log(LOGERROR, __FUNCTION__" - failed to lock texture."); } m_texture.UnlockRect(0); if (usage != D3D11_USAGE_STAGING && IsMipmapped()) m_texture.GenerateMipmaps(); } if (!m_bCacheMemory) { _aligned_free(m_pixels); m_pixels = nullptr; } m_loadedToGPU = true; }
void CGLTexture::LoadToGPU() { if (!m_pixels) { // nothing to load - probably same image (no change) return; } if (m_texture == 0) { // Have OpenGL generate a texture object handle for us // this happens only one time - the first time the texture is loaded CreateTextureObject(); } // Bind the texture object glBindTexture(GL_TEXTURE_2D, m_texture); GLenum filter = (m_scalingMethod == TEXTURE_SCALING::NEAREST ? GL_NEAREST : GL_LINEAR); // Set the texture's stretching properties if (IsMipmapped()) { GLenum mipmapFilter = (m_scalingMethod == TEXTURE_SCALING::NEAREST ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmapFilter); #ifndef HAS_GLES // Lower LOD bias equals more sharpness, but less smooth animation glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.5f); if (!m_isOglVersion3orNewer) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); #endif } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); unsigned int maxSize = CServiceBroker::GetRenderSystem()->GetMaxTextureSize(); if (m_textureHeight > maxSize) { CLog::Log(LOGERROR, "GL: Image height %d too big to fit into single texture unit, truncating to %u", m_textureHeight, maxSize); m_textureHeight = maxSize; } if (m_textureWidth > maxSize) { CLog::Log(LOGERROR, "GL: Image width %d too big to fit into single texture unit, truncating to %u", m_textureWidth, maxSize); #ifndef HAS_GLES glPixelStorei(GL_UNPACK_ROW_LENGTH, m_textureWidth); #endif m_textureWidth = maxSize; } #ifndef HAS_GLES GLenum format = GL_BGRA; GLint numcomponents = GL_RGBA; switch (m_format) { case XB_FMT_DXT1: format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case XB_FMT_DXT3: format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case XB_FMT_DXT5: case XB_FMT_DXT5_YCoCg: format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; case XB_FMT_RGB8: format = GL_RGB; numcomponents = GL_RGB; break; case XB_FMT_A8R8G8B8: default: break; } if ((m_format & XB_FMT_DXT_MASK) == 0) { glTexImage2D(GL_TEXTURE_2D, 0, numcomponents, m_textureWidth, m_textureHeight, 0, format, GL_UNSIGNED_BYTE, m_pixels); } else { glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, m_textureWidth, m_textureHeight, 0, GetPitch() * GetRows(), m_pixels); } if (IsMipmapped() && m_isOglVersion3orNewer) { glGenerateMipmap(GL_TEXTURE_2D); } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); #else // GLES version // All incoming textures are BGRA, which GLES does not necessarily support. // Some (most?) hardware supports BGRA textures via an extension. // If not, we convert to RGBA first to avoid having to swizzle in shaders. // Explicitly define GL_BGRA_EXT here in the case that it's not defined by // system headers, and trust the extension list instead. #ifndef GL_BGRA_EXT #define GL_BGRA_EXT 0x80E1 #endif GLint internalformat; GLenum pixelformat; switch (m_format) { default: case XB_FMT_RGBA8: internalformat = pixelformat = GL_RGBA; break; case XB_FMT_RGB8: internalformat = pixelformat = GL_RGB; break; case XB_FMT_A8R8G8B8: if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_EXT_texture_format_BGRA8888") || CServiceBroker::GetRenderSystem()->IsExtSupported("GL_IMG_texture_format_BGRA8888")) { internalformat = pixelformat = GL_BGRA_EXT; } else if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_APPLE_texture_format_BGRA8888")) { // Apple's implementation does not conform to spec. Instead, they require // differing format/internalformat, more like GL. internalformat = GL_RGBA; pixelformat = GL_BGRA_EXT; } else { SwapBlueRed(m_pixels, m_textureHeight, GetPitch()); internalformat = pixelformat = GL_RGBA; } break; } glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_textureWidth, m_textureHeight, 0, pixelformat, GL_UNSIGNED_BYTE, m_pixels); if (IsMipmapped()) { glGenerateMipmap(GL_TEXTURE_2D); } #endif VerifyGLState(); if (!m_bCacheMemory) { _aligned_free(m_pixels); m_pixels = NULL; } m_loadedToGPU = true; }
void CGLTexture::LoadToGPU() { if (!m_pixels) { // nothing to load - probably same image (no change) return; } if (m_texture == 0) { // Have OpenGL generate a texture object handle for us // this happens only one time - the first time the texture is loaded CreateTextureObject(); } // Bind the texture object glBindTexture(GL_TEXTURE_2D, m_texture); // Set the texture's stretching properties if (IsMipmapped()) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); #ifndef HAS_GLES // Lower LOD bias equals more sharpness, but less smooth animation glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.5f); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); #endif } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); unsigned int maxSize = g_Windowing.GetMaxTextureSize(); if (m_textureHeight > maxSize) { CLog::Log(LOGERROR, "GL: Image height %d too big to fit into single texture unit, truncating to %u", m_textureHeight, maxSize); m_textureHeight = maxSize; } if (m_textureWidth > maxSize) { CLog::Log(LOGERROR, "GL: Image width %d too big to fit into single texture unit, truncating to %u", m_textureWidth, maxSize); #ifndef HAS_GLES glPixelStorei(GL_UNPACK_ROW_LENGTH, m_textureWidth); m_textureWidth = maxSize; } GLenum format = GL_BGRA; GLint numcomponents = GL_RGBA; switch (m_format) { case XB_FMT_DXT1: format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case XB_FMT_DXT3: format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case XB_FMT_DXT5: case XB_FMT_DXT5_YCoCg: format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; case XB_FMT_RGB8: format = GL_RGB; numcomponents = GL_RGB; break; case XB_FMT_A8R8G8B8: default: break; } if ((m_format & XB_FMT_DXT_MASK) == 0) { glTexImage2D(GL_TEXTURE_2D, 0, numcomponents, m_textureWidth, m_textureHeight, 0, format, GL_UNSIGNED_BYTE, m_pixels); } else { // changed from glCompressedTexImage2D to support GL < 1.3 glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, format, m_textureWidth, m_textureHeight, 0, GetPitch() * GetRows(), m_pixels); } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); #else // GLES version m_textureWidth = maxSize; }