Textures: Add several defines and constructor options for compression, cache.
* Add defines `myouForceAstc`, `myouMinTextureChannels`, `myouLoadUncompressedTextures` and `myouAllCacheFilesExist`. * Suppress warning messages about emulation for `myouForceAstc`. * Add argument `use_compression` to `newTexture` (default `true`)
This commit is contained in:
parent
0192db3f67
commit
67307032da
4 changed files with 57 additions and 19 deletions
|
@ -138,7 +138,7 @@ proc loadFileFromSlices*(tex: Texture, slices: seq[SliceMem[byte]],
|
||||||
|
|
||||||
when not defined(nimdoc):
|
when not defined(nimdoc):
|
||||||
assert tex.tex_type != TexCube, "Loading a cube texture from file is not supported yet"
|
assert tex.tex_type != TexCube, "Loading a cube texture from file is not supported yet"
|
||||||
let format = if min_channels == 0:
|
let format = if min_channels <= tex.format.channel_count:
|
||||||
tex.format
|
tex.format
|
||||||
else:
|
else:
|
||||||
tex.format.resize(min_channels)
|
tex.format.resize(min_channels)
|
||||||
|
|
|
@ -68,14 +68,22 @@ when defined(nimdoc):
|
||||||
type TYPES* = CacheSettings | EncodingSpeed | RgbBcFmt | BlockSize
|
type TYPES* = CacheSettings | EncodingSpeed | RgbBcFmt | BlockSize
|
||||||
|
|
||||||
when defined(android) or defined(ios) or defined(emscripten):
|
when defined(android) or defined(ios) or defined(emscripten):
|
||||||
template has_bptc_support: bool = gl.GLAD_GL_EXT_texture_compression_bptc
|
template has_bptc_support: bool = gl.GLAD_GL_EXT_texture_compression_bptc and not defined(myouForceAstc)
|
||||||
else:
|
else:
|
||||||
template has_bptc_support: bool = gl.GLAD_GL_ARB_texture_compression_bptc
|
template has_bptc_support: bool = gl.GLAD_GL_ARB_texture_compression_bptc and not defined(myouForceAstc)
|
||||||
template has_astc_support: bool = gl.GLAD_GL_OES_texture_compression_astc or
|
template has_astc_support: bool = gl.GLAD_GL_OES_texture_compression_astc or
|
||||||
gl.GLAD_GL_KHR_texture_compression_astc_ldr
|
gl.GLAD_GL_KHR_texture_compression_astc_ldr or
|
||||||
|
defined(ios) or
|
||||||
|
defined(myouForceAstc)
|
||||||
|
|
||||||
|
const myouMinTextureChannels {.intdefine.} = 0
|
||||||
const myouEngineNumTextureThreads {.intdefine.} = 4
|
const myouEngineNumTextureThreads {.intdefine.} = 4
|
||||||
const myouBC7VerboseMode {.booldefine.} = false
|
const myouBC7VerboseMode {.booldefine.} = false
|
||||||
|
const myouAllCacheFilesExist {.booldefine.} = defined(myouUseAndroidAssets)
|
||||||
|
const myouLoadUncompressedTextures {.booldefine.} = false
|
||||||
|
when defined(myouAllCacheFilesExist):
|
||||||
|
import ../platform/platform
|
||||||
|
import std/strutils
|
||||||
|
|
||||||
template u32(x: untyped): uint32 = cast[uint32](x)
|
template u32(x: untyped): uint32 = cast[uint32](x)
|
||||||
|
|
||||||
|
@ -90,7 +98,7 @@ template block_file_size(width, height, depth, block_x, block_y, block_z, block_
|
||||||
let blocks_z = (depth.int + block_z.int - 1) div block_z.int
|
let blocks_z = (depth.int + block_z.int - 1) div block_z.int
|
||||||
blocks_x * blocks_y * blocks_z * block_byte_size.int
|
blocks_x * blocks_y * blocks_z * block_byte_size.int
|
||||||
|
|
||||||
proc make_mipmaps(tex: Texture, pixels: SliceMem[byte], compress: CompressMipmap): (seq[KtxPart], seq[SliceMem[byte]]) =
|
proc make_mipmaps(tex: Texture, pixels: SliceMem[byte], compress: CompressMipmap, fmt_debug: string): (seq[KtxPart], seq[SliceMem[byte]]) =
|
||||||
var width = tex.width.int32
|
var width = tex.width.int32
|
||||||
var height = tex.height.int32
|
var height = tex.height.int32
|
||||||
let depth = tex.format_depth
|
let depth = tex.format_depth
|
||||||
|
@ -147,7 +155,7 @@ proc make_mipmaps(tex: Texture, pixels: SliceMem[byte], compress: CompressMipmap
|
||||||
h = max(1, h shr 1)
|
h = max(1, h shr 1)
|
||||||
mip_level.inc
|
mip_level.inc
|
||||||
let time2 = getmonotime().ticks.float/1000000000
|
let time2 = getmonotime().ticks.float/1000000000
|
||||||
echo "time: ", time2-time, " ", tex.name
|
echo "time: ", time2-time, " ", tex.name, " ", fmt_debug
|
||||||
return (parts, data_refs)
|
return (parts, data_refs)
|
||||||
|
|
||||||
when defined(myouUseBC7Encoder):
|
when defined(myouUseBC7Encoder):
|
||||||
|
@ -183,7 +191,7 @@ when defined(myouUseBC7Encoder):
|
||||||
assert err == NO_ERROR, "bc7enc error: " & $err
|
assert err == NO_ERROR, "bc7enc error: " & $err
|
||||||
return (data, row_len)
|
return (data, row_len)
|
||||||
|
|
||||||
let (parts, data_refs) = make_mipmaps(tex, pixels, compress)
|
let (parts, data_refs) = make_mipmaps(tex, pixels, compress, "bc")
|
||||||
|
|
||||||
let info = KtxInfo(
|
let info = KtxInfo(
|
||||||
width: parts[0].width, height: parts[0].height, depth: tex.format_depth.int32,
|
width: parts[0].width, height: parts[0].height, depth: tex.format_depth.int32,
|
||||||
|
@ -256,7 +264,7 @@ when defined(myouUseAstcEncoder):
|
||||||
assert err == ASTCENC_SUCCESS, "ASTC encoding error: " & $err
|
assert err == ASTCENC_SUCCESS, "ASTC encoding error: " & $err
|
||||||
return (data, row_len)
|
return (data, row_len)
|
||||||
|
|
||||||
let (parts, data_refs) = make_mipmaps(tex, pixels, compress)
|
let (parts, data_refs) = make_mipmaps(tex, pixels, compress, "astc")
|
||||||
|
|
||||||
let blk = (blk_size.first, blk_size.second)
|
let blk = (blk_size.first, blk_size.second)
|
||||||
let info = KtxInfo(
|
let info = KtxInfo(
|
||||||
|
@ -274,12 +282,12 @@ func `%`(p: pointer): JsonNode = %0
|
||||||
proc loadOptimized*(tex: Texture, slices: seq[SliceMem[byte]],
|
proc loadOptimized*(tex: Texture, slices: seq[SliceMem[byte]],
|
||||||
callback_uncompressed: CallbackUncompressed = nil,
|
callback_uncompressed: CallbackUncompressed = nil,
|
||||||
callback_compressed: CallbackCompressed = nil,
|
callback_compressed: CallbackCompressed = nil,
|
||||||
flip = true, min_channels = 0) {.gcsafe.} =
|
flip = true, min_channels = myouMinTextureChannels) {.gcsafe.} =
|
||||||
|
|
||||||
let settings = tex.engine.cache_settings
|
let settings = tex.engine.cache_settings
|
||||||
var min_channels = min_channels
|
var min_channels = min_channels
|
||||||
var will_compress = settings.compress_textures
|
var will_compress = settings.compress_textures
|
||||||
var will_load_uncompressed_first = false
|
var will_load_uncompressed_first = myouLoadUncompressedTextures
|
||||||
var will_encode_all = settings.compress_all_formats
|
var will_encode_all = settings.compress_all_formats
|
||||||
|
|
||||||
will_compress = will_compress and
|
will_compress = will_compress and
|
||||||
|
@ -302,16 +310,28 @@ proc loadOptimized*(tex: Texture, slices: seq[SliceMem[byte]],
|
||||||
if settings.use_cache and callback_compressed != nil:
|
if settings.use_cache and callback_compressed != nil:
|
||||||
let cache_file = settings.cache_dir & "/" & cache_file_name
|
let cache_file = settings.cache_dir & "/" & cache_file_name
|
||||||
# TODO: allow networked requests
|
# TODO: allow networked requests
|
||||||
if fileExists cache_file:
|
if myouAllCacheFilesExist or fileExists cache_file:
|
||||||
try:
|
try:
|
||||||
|
when defined(myouUseAndroidAssets):
|
||||||
|
var asset = myouAndroidAPKFilePointerLength(cache_file.split("/", 1)[1])
|
||||||
|
var f = newString(asset.len)
|
||||||
|
copyMem(f.cstring.pointer, asset.p, asset.len)
|
||||||
|
let slices = f.decompress.toSliceMem.to(byte).deserialize
|
||||||
|
elif defined(ios) and myouAllCacheFilesExist:
|
||||||
|
let cache_file = myouGetBundledFilePath("assets/" & cache_file.split("/", 1)[1])
|
||||||
|
let slices = readFile(cache_file).decompress.toSliceMem.to(byte).deserialize
|
||||||
|
else:
|
||||||
let slices = readFile(cache_file).decompress.toSliceMem.to(byte).deserialize
|
let slices = readFile(cache_file).decompress.toSliceMem.to(byte).deserialize
|
||||||
var data = to[KtxInfoParts](slices[^1].toString)
|
var data = to[KtxInfoParts](slices[^1].toString)
|
||||||
for i,p in data.parts.mpairs:
|
for i,p in data.parts.mpairs:
|
||||||
p.data = slices[i].toPointer
|
p.data = slices[i].toPointer
|
||||||
tex.callback_compressed(data, slices)
|
tex.callback_compressed(data, slices)
|
||||||
return
|
return
|
||||||
except:
|
except Exception as e:
|
||||||
|
echo e.getStackTrace()
|
||||||
|
echo getCurrentExceptionMsg()
|
||||||
# TODO: proper error handling and logging
|
# TODO: proper error handling and logging
|
||||||
|
echo cache_file
|
||||||
echo "ERROR: could not load cache file for " & tex.name
|
echo "ERROR: could not load cache file for " & tex.name
|
||||||
|
|
||||||
if not (native_bc or native_astc):
|
if not (native_bc or native_astc):
|
||||||
|
@ -344,7 +364,7 @@ proc loadOptimized*(tex: Texture, slices: seq[SliceMem[byte]],
|
||||||
|
|
||||||
let channels = tex.format.channel_count
|
let channels = tex.format.channel_count
|
||||||
|
|
||||||
when defined(myouUseBC7Encoder):
|
when defined(myouUseBC7Encoder) and not defined(myouForceAstc):
|
||||||
if has_bptc_support or will_encode_all:
|
if has_bptc_support or will_encode_all:
|
||||||
let bc_format = if channels == 1:
|
let bc_format = if channels == 1:
|
||||||
4.int8 # BC4
|
4.int8 # BC4
|
||||||
|
@ -391,7 +411,7 @@ when compileOption("threads"):
|
||||||
proc loadOptimizedThreaded*(tex: Texture, slices: seq[SliceMem[byte]],
|
proc loadOptimizedThreaded*(tex: Texture, slices: seq[SliceMem[byte]],
|
||||||
callback_uncompressed: CallbackUncompressed = nil,
|
callback_uncompressed: CallbackUncompressed = nil,
|
||||||
callback_compressed: CallbackCompressed = nil,
|
callback_compressed: CallbackCompressed = nil,
|
||||||
flip = true, min_channels = 0) =
|
flip = true, min_channels = myouMinTextureChannels) =
|
||||||
|
|
||||||
when not compileOption("threads"):
|
when not compileOption("threads"):
|
||||||
loadOptimized(tex, slices, callback_uncompressed, callback_compressed, flip, min_channels)
|
loadOptimized(tex, slices, callback_uncompressed, callback_compressed, flip, min_channels)
|
||||||
|
|
|
@ -59,11 +59,14 @@ proc newTexture*(engine: MyouEngine, name: string, width, height: int, depth: in
|
||||||
pixels: ArrRef[float32] = nil): Texture
|
pixels: ArrRef[float32] = nil): Texture
|
||||||
proc generateMipmap*(self: Texture)
|
proc generateMipmap*(self: Texture)
|
||||||
func to_sRGB*(format: TextureFormat): TextureFormat
|
func to_sRGB*(format: TextureFormat): TextureFormat
|
||||||
proc newTexture*(engine: MyouEngine, name: string, data: SliceMem[byte], is_sRGB: bool, filter: TextureFilter = Trilinear, depth=1, flip=true): Texture
|
proc newTexture*(engine: MyouEngine, name: string, data: SliceMem[byte],
|
||||||
|
is_sRGB: bool, filter: TextureFilter = Trilinear, depth=1,
|
||||||
|
flip = true, use_compression = true): Texture
|
||||||
proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: bool,
|
proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: bool,
|
||||||
filter: TextureFilter = Trilinear,
|
filter: TextureFilter = Trilinear,
|
||||||
tex_type: TextureType = Tex2D,
|
tex_type: TextureType = Tex2D,
|
||||||
flip = true,
|
flip = true,
|
||||||
|
use_compression = true,
|
||||||
): Texture
|
): Texture
|
||||||
proc setExtrapolation*(self: Texture, ext: TextureExtrapolation)
|
proc setExtrapolation*(self: Texture, ext: TextureExtrapolation)
|
||||||
proc getTexturePixels*(self: Texture): TexturePixels
|
proc getTexturePixels*(self: Texture): TexturePixels
|
||||||
|
@ -440,7 +443,9 @@ func to_sRGB*(format: TextureFormat): TextureFormat =
|
||||||
of RGB_u8: SRGB_u8
|
of RGB_u8: SRGB_u8
|
||||||
else: raise newException(ValueError, "There's no sRGB version of " & $format)
|
else: raise newException(ValueError, "There's no sRGB version of " & $format)
|
||||||
|
|
||||||
proc newTexture*(engine: MyouEngine, name: string, data: SliceMem[byte], is_sRGB: bool, filter: TextureFilter = Trilinear, depth=1, flip=true): Texture =
|
proc newTexture*(engine: MyouEngine, name: string, data: SliceMem[byte],
|
||||||
|
is_sRGB: bool, filter: TextureFilter = Trilinear, depth=1,
|
||||||
|
flip = true, use_compression = true): Texture =
|
||||||
var (width, height, format) = getDimensionsFormat(data.data, data.byte_len)
|
var (width, height, format) = getDimensionsFormat(data.data, data.byte_len)
|
||||||
if is_sRGB:
|
if is_sRGB:
|
||||||
if format in [RGB_u8, RGBA_u8]:
|
if format in [RGB_u8, RGBA_u8]:
|
||||||
|
@ -451,13 +456,17 @@ proc newTexture*(engine: MyouEngine, name: string, data: SliceMem[byte], is_sRGB
|
||||||
let self = engine.newTexture(name, width, height, depth, format, filter=filter)
|
let self = engine.newTexture(name, width, height, depth, format, filter=filter)
|
||||||
self.is_sRGB = is_sRGB
|
self.is_sRGB = is_sRGB
|
||||||
engine.renderer.enqueue proc() =
|
engine.renderer.enqueue proc() =
|
||||||
|
if use_compression:
|
||||||
self.loadOptimizedThreaded(@[data], loadFromPixels, loadCompressedData)
|
self.loadOptimizedThreaded(@[data], loadFromPixels, loadCompressedData)
|
||||||
|
else:
|
||||||
|
self.loadOptimizedThreaded(@[data], loadFromPixels, nil)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: bool,
|
proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: bool,
|
||||||
filter: TextureFilter = Trilinear,
|
filter: TextureFilter = Trilinear,
|
||||||
tex_type: TextureType = Tex2D,
|
tex_type: TextureType = Tex2D,
|
||||||
flip = true,
|
flip = true,
|
||||||
|
use_compression = true,
|
||||||
): Texture =
|
): Texture =
|
||||||
|
|
||||||
# TODO: Api that stores the LoadableResource so it can be re-loaded later
|
# TODO: Api that stores the LoadableResource so it can be re-loaded later
|
||||||
|
@ -506,7 +515,10 @@ proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: b
|
||||||
engine.renderer.enqueue proc()=
|
engine.renderer.enqueue proc()=
|
||||||
try:
|
try:
|
||||||
self.ensure_storage()
|
self.ensure_storage()
|
||||||
|
if use_compression:
|
||||||
self.loadOptimizedThreaded(@[data], loadFromPixels, loadCompressedData)
|
self.loadOptimizedThreaded(@[data], loadFromPixels, loadCompressedData)
|
||||||
|
else:
|
||||||
|
self.loadOptimizedThreaded(@[data], loadFromPixels, nil)
|
||||||
except:
|
except:
|
||||||
# TODO: use logging
|
# TODO: use logging
|
||||||
echo getCurrentExceptionMsg()
|
echo getCurrentExceptionMsg()
|
||||||
|
|
|
@ -50,6 +50,8 @@ when compileOption("threads"):
|
||||||
from loadable import terminateLoadableWorkerThreads
|
from loadable import terminateLoadableWorkerThreads
|
||||||
from ../gpu_formats/texture_optimize import terminateTextureWorkerThreads
|
from ../gpu_formats/texture_optimize import terminateTextureWorkerThreads
|
||||||
|
|
||||||
|
func c_strstr(haystack, needle: cstring): cstring {.importc: "strstr", header: "<string.h>".}
|
||||||
|
|
||||||
proc screen*(window: Window): Screen {.inline.} =
|
proc screen*(window: Window): Screen {.inline.} =
|
||||||
cast[Screen](window.getWindowUserPointer)
|
cast[Screen](window.getWindowUserPointer)
|
||||||
|
|
||||||
|
@ -211,6 +213,10 @@ proc init_graphics*(engine: MyouEngine, width, height: int32, title: string,
|
||||||
if max_messages == 0:
|
if max_messages == 0:
|
||||||
return
|
return
|
||||||
# dump (source, etype, id, severity, length)
|
# dump (source, etype, id, severity, length)
|
||||||
|
when defined(myouForceAstc):
|
||||||
|
# Supress warnings when forcing astc on desktop
|
||||||
|
if c_strstr(message, "emulating compressed format") != nil:
|
||||||
|
return
|
||||||
echo getStackTrace().rsplit('\n',3)[1]
|
echo getStackTrace().rsplit('\n',3)[1]
|
||||||
echo "OpenGL error: ", message
|
echo "OpenGL error: ", message
|
||||||
max_messages -= 1
|
max_messages -= 1
|
||||||
|
|
Loading…
Reference in a new issue