Texture importer now supports mip maps

This commit is contained in:
Simon Lübeß
2023-07-06 17:06:59 +02:00
parent a507eeb1cd
commit 76bff3a6c1
9 changed files with 631 additions and 168 deletions
+250 -32
View File
@@ -48,7 +48,10 @@ static class DdsImporter
{
Unknown,
WrongMagicWord,
StreamReadFailed
StreamReadFailed,
InvalidArraySize,
WrongDimensions,
IncompleteCubemap
}
private enum HeaderFlags : uint32
@@ -274,45 +277,91 @@ static class DdsImporter
DdsPixelFormat pixelFormat = header.PixelFormat;
// Currently supports only basic dxgi formats.
if (pixelFormat.SurfaceType.HasFlag(.RGBA))
{
switch (pixelFormat.RGBBitCount)
{
case 32:
if (IsBitMask(pixelFormat, 0xFF, 0xFF00, 0xFF0000, 0xFF000000))
return isSrgb ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm;
if (IsBitMask(pixelFormat, 0xffff, 0xffff0000, 0x0, 0x0))
return .R16G16_UNorm;
if (IsBitMask(pixelFormat, 0x3ff, 0xffc00, 0x3ff00000, 0x0))
return .R10G10B10A2_UNorm;
case 16:
if (IsBitMask(pixelFormat, 0x7c00, 0x3e0, 0x1f, 0x8000))
return .B5G5R5A1_UNorm;
default:
return .Unknown;
}
}
//if (pixelFormat.SurfaceType.HasFlag(.RGBA))
if (pixelFormat.SurfaceType.HasFlag(.RGB))
{
switch (pixelFormat.RGBBitCount)
{
case 32:
if (IsBitMask(pixelFormat, 0xffff, 0xffff0000, 0x0, 0x0))
if (IsBitMask(pixelFormat, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000))
return isSrgb ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm;
if (IsBitMask(pixelFormat, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000))
return isSrgb ? .B8G8R8A8_UNorm_SRGB : .B8G8R8A8_UNorm;
if (IsBitMask(pixelFormat, 0x00FF0000, 0x0000FF00, 0x000000FF, 0))
return isSrgb ? .B8G8R8X8_UNorm_SRGB : .B8G8R8X8_UNorm;
if (IsBitMask(pixelFormat, 0x000003FF, 0x000FFc00, 0x3FF00000, 0))
return .R10G10B10A2_UNorm;
if (IsBitMask(pixelFormat, 0x3FF00000, 0x000FFc00, 0x000003FF, 0))
return .R10G10B10A2_UNorm;
if (IsBitMask(pixelFormat, 0x0000FFFF, 0xFFFF0000, 0, 0))
return .R16G16_UNorm;
break;
if (IsBitMask(pixelFormat, 0xFFFFFFFF, 0, 0, 0))
return .R32_Float;
case 24:
// NO 24 bit formats
return .Unknown;
case 16:
if (IsBitMask(pixelFormat, 0xf800, 0x7e0, 0x1f, 0x0))
if (IsBitMask(pixelFormat, 0x7C00, 0x03E0, 0x001F, 0x8000))
return .B5G5R5A1_UNorm;
if (IsBitMask(pixelFormat, 0xF800, 0x07E0, 0x001F, 0))
return .B5G6R5_UNorm;
break;
if (IsBitMask(pixelFormat, 0x0F00, 0x00F0, 0x000F, 0xF000))
return .B4G4R4A4_UNORM;
if (IsBitMask(pixelFormat, 0x00FF, 0, 0, 0xFF00))
return .R8G8_UNorm;
if (IsBitMask(pixelFormat, 0xFFFF, 0, 0, 0))
return .R16_UNorm;
case 8:
if (IsBitMask(pixelFormat, 0xFF, 0, 0, 0))
return .R8_UNorm;
default:
return .Unknown;
}
}
else if (pixelFormat.SurfaceType.HasFlag(.Luminance))
{
switch (pixelFormat.RGBBitCount)
{
case 16:
if (IsBitMask(pixelFormat, 0xFFFF, 0, 0, 0))
return .R16_UNorm;
if (pixelFormat.SurfaceType.HasFlag(.FourCC))
if (IsBitMask(pixelFormat, 0x00FF, 0, 0, 0xFF00))
return .R8G8_UNorm;
case 8:
if (IsBitMask(pixelFormat, 0xFF, 0, 0, 0))
return .R8_UNorm;
if (IsBitMask(pixelFormat, 0x00FF, 0, 0, 0xFF00))
return .R8G8_UNorm; // Some DDS writers assume the bitcount should be 8 instead of 16
default:
return .Unknown;
}
}
else if (pixelFormat.SurfaceType.HasFlag(.Luminance))
{
if (pixelFormat.RGBBitCount == 8)
{
return .A8_UNorm;
}
}
else if (pixelFormat.SurfaceType.HasFlag(.FourCC))
{
switch (pixelFormat.FourCC)
{
@@ -322,15 +371,30 @@ static class DdsImporter
return isSrgb ? .BC2_UNorm_SRGB : .BC2_UNorm;
case MakeFourCC('D', 'X', 'T', '5'):
return isSrgb ? .BC3_UNorm_SRGB : .BC3_UNorm;
// Legacy compression formats.
case MakeFourCC('D', 'X', 'T', '2'):
return isSrgb ? .BC2_UNorm_SRGB : .BC2_UNorm;
case MakeFourCC('D', 'X', 'T', '4'):
return isSrgb ? .BC3_UNorm_SRGB : .BC3_UNorm;
case MakeFourCC('B', 'C', '4', 'U'), MakeFourCC('A', 'T', 'I', '1'):
return .BC4_UNorm;
case MakeFourCC('A', 'T', 'I', '2'):
case MakeFourCC('B', 'C', '4', 'S'):
return .BC4_SNorm;
case MakeFourCC('B', 'C', '5', 'U'), MakeFourCC('A', 'T', 'I', '2'):
return .BC5_UNorm;
case MakeFourCC('B', 'C', '5', 'S'):
return .BC5_SNorm;
case MakeFourCC('R', 'G', 'B', 'G'):
return .R8G8_B8G8_UNorm;
case MakeFourCC('G', 'R', 'G', 'B'):
return .G8R8_G8B8_UNorm;
case MakeFourCC('Y', 'U', 'Y', '2'):
return .YUY2;
case 36:
return .R16G16B16A16_UNorm;
case 111:
@@ -353,8 +417,137 @@ static class DdsImporter
return .Unknown;
}
public static void GetPitch(uint32 width, uint32 height, DirectX.DXGI.Format format, out uint32 rowBytes, out uint32 numRows, out uint64 numBytes)
{
rowBytes = 0;
numRows = 0;
numBytes = 0;
bool bc = false;
bool packed = false;
bool planar = false;
uint32 bpe = 0;
switch (format)
{
case .BC1_Typeless, .BC1_UNorm, .BC1_UNorm_SRGB,
.BC4_Typeless, .BC4_UNorm, .BC4_SNorm:
bc = true;
bpe = 8;
break;
case .BC2_Typeless, .BC2_UNorm, .BC2_UNorm_SRGB,
.BC3_Typeless, .BC3_UNorm, .BC3_UNorm_SRGB,
.BC5_Typeless, .BC5_UNorm, .BC5_SNorm,
.BC6H_Typeless, .BC6H_UF16, .BC6H_SF16,
.BC7_Typeless, .BC7_UNorm, .BC7_UNorm_SRGB:
bc = true;
bpe = 16;
break;
case .R8G8_B8G8_UNorm, .G8R8_G8B8_UNorm, .YUY2:
packed = true;
bpe = 4;
break;
case .Y210, .Y216:
packed = true;
bpe = 8;
break;
case .NV12, .P208, .OPAQUE_420:
planar = true;
bpe = 2;
break;
case .P010, .P016:
planar = true;
bpe = 4;
break;
/*
case .D16_UNORM_S8_UINT:
case .R16_UNORM_X8_TYPELESS:
case .X16_TYPELESS_G8_UINT:
planar = true;
bpe = 4;
break;
*/
default:
break;
}
if (bc)
{
uint32 numBlocksWide = 0;
if (width > 0)
{
numBlocksWide = Math.Max(1, (width + 3u) / 4u);
}
uint32 numBlocksHigh = 0;
if (height > 0)
{
numBlocksHigh = Math.Max(1, (height + 3u) / 4u);
}
rowBytes = numBlocksWide * bpe;
numRows = numBlocksHigh;
numBytes = rowBytes * numBlocksHigh;
}
else if (packed)
{
rowBytes = (((uint32)width + 1u) >> 1) * bpe;
numRows = height;
numBytes = rowBytes * height;
}
else if (format == .NV11)
{
rowBytes = ((width + 3u) >> 2) * 4u;
numRows = height * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
numBytes = rowBytes * numRows;
}
else if (planar)
{
rowBytes = ((width + 1u) >> 1) * bpe;
numBytes = (rowBytes * height) + ((rowBytes * height + 1u) >> 1);
numRows = height + ((height + 1u) >> 1);
}
else
{
uint32 bpp = format.BitsPerPixel();// BitsPerPixel(format);
if (bpp == 0)
return;
rowBytes = (width * bpp + 7u) / 8u; // round up to nearest byte
numRows = height;
numBytes = rowBytes * height;
}
//#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
/*static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);*/
/*#else
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
#endif*/
/*if (outNumBytes)
{
*outNumBytes = static_cast<size_t>(numBytes);
}
if (outRowBytes)
{
*outRowBytes = static_cast<size_t>(rowBytes);
}
if (outNumRows)
{
*outNumRows = static_cast<size_t>(numRows);
}*/
}
public static Result<void, LoadError> LoadDds(Stream data, bool isSrgb, List<LoadedSurface> surfaces, out LoadedTextureInfo textureInfo)
{
// TODO: Care about alpha mode
textureInfo = .();
var headerResult = DecodeHeader(data, let header, let extendedHeader);
@@ -384,6 +577,9 @@ static class DdsImporter
{
textureInfo.ArraySize = extendedHeader.Value.ArraySize;
surfaceCount *= textureInfo.ArraySize;
if (textureInfo.ArraySize == 0)
return .Err(.InvalidArraySize);
}
else
{
@@ -409,15 +605,28 @@ static class DdsImporter
{
case .Texture1D:
textureInfo.Dimension = .Texture1D;
if (header.Flags.HasFlag(.DDSD_HEIGHT) && header.Height != 1)
return .Err(.WrongDimensions);
textureInfo.Height = 1;
textureInfo.Depth = 1;
case .Texture2D:
textureInfo.Dimension = .Texture2D;
textureInfo.Depth = 1;
case .Texture3D:
textureInfo.Dimension = .Texture3D;
case null:
if (header.Flags.HasFlag(.DDSD_DEPTH))
textureInfo.Dimension = .Texture3D;
else
{
textureInfo.Dimension = .Texture2D;
textureInfo.Depth = 1;
}
}
// Make sure we have enough space in the list (avoid allocations later)
@@ -425,7 +634,7 @@ static class DdsImporter
uint32 scanLineSize = 0;
uint32 slicePitch = 0;
uint32 numBytes = 0;
uint64 numBytes = 0;
uint32 blockSize = 0; // Block size in bytes.
switch (textureInfo.PixelFormat)
@@ -459,7 +668,7 @@ static class DdsImporter
for (uint32 mipLevel = 0; mipLevel < textureInfo.MipMapCount; ++mipLevel)
{
// This will recalculate te pitch of the main image as well.
/*// This will recalculate te pitch of the main image as well.
if (header.Flags.HasFlag(.DDSD_LINEARSIZE))
{
// compressed textures
@@ -473,13 +682,22 @@ static class DdsImporter
scanLineSize = (width * header.PixelFormat.RGBBitCount + 7u) / 8u;
numBytes = scanLineSize * height;
}
else
{
scanLineSize = header.PitchOrLinearSize;
numBytes = scanLineSize * height;
}*/
GetPitch(width, height, textureInfo.PixelFormat, out scanLineSize, let numRows, out numBytes);
LoadedSurface surface = .();
// We don't know how large data-array is, so we don't have one yet.
// Only save the offset, we will adjust the pointer later.
surface.Data = Span<uint8>((uint8*)(void*)offset, numBytes);
surface.Data = Span<uint8>((uint8*)(void*)offset, (int)numBytes);
surface.Pitch = scanLineSize;
surface.SlicePitch = slicePitch;
//surface.SlicePitch = slicePitch;
surface.SlicePitch = scanLineSize * numRows;
surface.ArrayIndex = arrayIndex;
surface.CubeFace = cubeFace;
+62 -3
View File
@@ -9,6 +9,7 @@ using GlitchyEngine.Math;
using DirectXTK;
using ImGui;
using GlitchyEditor.Assets.Importers;
using System.Diagnostics;
namespace GlitchyEditor.Assets;
@@ -165,6 +166,9 @@ class EditorTextureAssetLoaderConfig : AssetLoaderConfig
}
}
using internal GlitchyEngine.Renderer;
using internal GlitchyEngine.Platform.DX11;
class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
{
private static readonly List<StringView> _fileExtensions = new .(){".png", ".dds"} ~ delete _; // ".jpg", ".bmp"
@@ -231,6 +235,35 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
return .Unknown;
}
/** \brief Loads the texture from the specified path.
* @param path The path of the texture to load.
* @param texture The reference to the pointer that will hold the texture.
* @returns true if the texture was loaded successfully; false otherwise.
*/
protected static bool LoadDdsResourcePlatform(Stream stream)
{
Debug.Profiler.ProfileResourceFunction!();
uint8[] ddsData = new:ScopedAlloc! uint8[stream.Length];
var result = stream.TryRead(ddsData);
if (result case .Err(let err))
{
Log.EngineLogger.Error($"Failed to read texture data from stream. Error: {err}");
}
DirectX.D3D11.ID3D11Texture2D* texture = null;
DirectX.D3D11.ID3D11ShaderResourceView* view = null;
DirectX.Common.HResult loadResult = DDSTextureLoader.CreateDDSTextureFromMemory(GlitchyEngine.Platform.DX11.NativeDevice,
ddsData.Ptr, (uint)ddsData.Count, (.)&texture, &view);
view.Release();
return true;
}
private static Texture LoadTexture(Stream data, EditorTextureAssetLoaderConfig config)
{
Debug.Profiler.ProfileResourceFunction!();
@@ -245,6 +278,13 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
switch(GetTextureType(data))
{
case .DDS:
var v = data.Position;
//LoadDdsResourcePlatform(data);
data.Position = v;
Result<void> result = LoadDds(data, config, surfaces, out textureInfo);
if (result case .Err)
@@ -261,6 +301,12 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
return null;
}
// Make the format SRGB or non-SRGB
if (config.IsSRGB)
textureInfo.PixelFormat = textureInfo.PixelFormat.GetSRGB();
else
textureInfo.PixelFormat = textureInfo.PixelFormat.GetNonSRGB();
Texture texture = CreateTexture(surfaces, textureInfo);
if (texture != null)
@@ -274,6 +320,15 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
private static Texture CreateTexture(List<LoadedSurface> surfaces, LoadedTextureInfo textureInfo)
{
TextureSliceData[] slices = scope TextureSliceData[surfaces.Count];
for (int i < slices.Count)
{
slices[i] = .(surfaces[i].Data.Ptr, surfaces[i].Pitch, surfaces[i].SlicePitch);
}
//slices[0].SlicePitch = (.)(surfaces[0].Pitch * textureInfo.Height);
switch (textureInfo.Dimension)
{
//case .Texture1D:
@@ -296,6 +351,8 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
TextureCube cubeTexture = new TextureCube(staging);
//cubeTexture.SetData();
for (let surface in surfaces)
{
cubeTexture.SetData(surface.Data.Ptr, surface.Pitch / staging.Width, (TextureCubeFace)surface.CubeFace, (.)surface.ArrayIndex, (.)surface.MipLevel);
@@ -317,14 +374,16 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
// TODO: allow enabling read/write
staging.CpuAccess = .None;
staging.Usage = .Default;
staging.Usage = .Immutable;
Texture2D stagingTexture = new Texture2D(staging);
for (let surface in surfaces)
stagingTexture.SetData(slices);
/*for (let surface in surfaces)
{
stagingTexture.[Friend]PlatformSetData(surface.Data.Ptr, surface.Pitch / staging.Width, 0, 0, staging.Width, staging.Height, (.)surface.ArrayIndex, (.)surface.MipLevel, .Write);
}
}*/
return stagingTexture;
}
+64 -115
View File
@@ -201,31 +201,6 @@ class TexturererViewerer
ColorChannelSwizzle _swizzleB = .B;
ColorChannelSwizzle _swizzleA = .A;
public void ViewTexture(RenderTargetGroup texture)
{
ShowSettings(texture.Width, texture.Height, texture.MipLevels - 1, texture.ArraySize - 1, texture);
UpdateInput();
var viewportSize = ImGui.GetContentRegionAvail();
viewportSize.x = Math.Max(viewportSize.x, 1);
viewportSize.y = Math.Max(viewportSize.y, 1);
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height)
{
_target?.ReleaseRef();
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm, (.)viewportSize.x, (.)viewportSize.y));
_target.SamplerState = SamplerStateManager.PointClamp;
_depth?.ReleaseRef();
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
}
RenderTexture(texture);
ImGui.Image(_target, viewportSize);
}
public void ShowSettings(float width, float height, int maxMips, int arraySize, RenderTargetGroup rtGroup)
{
char8*[] items = scope .("White", "Black", "Pink", "Checkerboard", "Custom Color");
@@ -382,6 +357,38 @@ class TexturererViewerer
}
}
public void ViewTexture(RenderTargetGroup texture)
{
ShowSettings(texture.Width, texture.Height, texture.MipLevels - 1, texture.ArraySize - 1, texture);
if (ImGui.BeginChild("imageChild"))
{
UpdateInput();
var viewportSize = ImGui.GetContentRegionAvail();
viewportSize.x = Math.Max(viewportSize.x, 1);
viewportSize.y = Math.Max(viewportSize.y, 1);
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height)
{
_target?.ReleaseRef();
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm_SRGB, (.)viewportSize.x, (.)viewportSize.y));
_target.SamplerState = SamplerStateManager.PointClamp;
_depth?.ReleaseRef();
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
}
RenderBackground();
RenderTexture(texture);
ImGui.Image(_target, viewportSize);
ImGui.EndChild();
}
}
public void ViewTexture(Texture texture)
{
ShowSettings(texture.Width, texture.Height, texture.MipLevels - 1, texture.ArraySize - 1, null);
@@ -398,12 +405,14 @@ class TexturererViewerer
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height)
{
_target?.ReleaseRef();
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm, (.)viewportSize.x, (.)viewportSize.y));
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm_SRGB, (.)viewportSize.x, (.)viewportSize.y));
_target.SamplerState = SamplerStateManager.PointClamp;
_depth?.ReleaseRef();
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
}
RenderBackground();
RenderTexture(texture);
ImGui.Image(_target, viewportSize);
@@ -461,7 +470,7 @@ class TexturererViewerer
OrthographicCamera _camera = new OrthographicCamera() ~ delete _;
private void RenderTexture(RenderTargetGroup viewedTexture)
private void RenderBackground()
{
Viewport vp = .(0, 0, _target.Width, _target.Height);
RenderCommand.SetViewport(vp);
@@ -475,9 +484,6 @@ class TexturererViewerer
RenderCommand.SetDepthStencilTarget(_depth);
RenderCommand.BindRenderTargets();
float2 textureSize = float2(viewedTexture.Width, viewedTexture.Height);
float2 zoomedTextureSize = textureSize * _zoom;
float2 targetSize = float2(_target.Width, _target.Height);
_camera.Left = 0;
@@ -516,6 +522,17 @@ class TexturererViewerer
}
Renderer2D.EndScene();
}
private void RenderTexture(TextureViewBinding viewedTexture, float2 textureSize, Format format)
{
float2 mippedTextureSize = float2((int)textureSize.X >> _mipLevel, (int)textureSize.X >> _mipLevel);
// Sicherstellen, dass die Auflösung nicht 0 wird
mippedTextureSize = max(mippedTextureSize, 1);
//float2 textureSize = float2(viewedTexture.Width, viewedTexture.Height);
float2 zoomedTextureSize = textureSize * _zoom;
// TODO: Sampler state for rt group
//var sampler = viewedTexture.SamplerState;
@@ -542,34 +559,35 @@ class TexturererViewerer
_renderTargetEffect.Variables["AlphaOffset"].SetData(_alphaOffset);
_renderTargetEffect.Variables["AlphaScale"].SetData(_alphaScale);
_renderTargetEffect.Variables["Texels"].SetData(float2(viewedTexture.Width, viewedTexture.Height));
_renderTargetEffect.Variables["Texels"].SetData(mippedTextureSize);
_renderTargetEffect.Variables["MipLevel"].SetData((float)_mipLevel);
_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
var desc = _groupIndex >= 0 ? viewedTexture.[Friend]_colorTargetDescriptions[_groupIndex] : viewedTexture.[Friend]_depthTargetDescription;
if (desc.Format.IsInt())
if (format.IsInt())
{
// Int Texture
_renderTargetEffect.Variables["Mode"].SetData(1);
_renderTargetEffect.SetTexture("IntTexture", viewedTexture.GetViewBinding(_groupIndex));
_renderTargetEffect.SetTexture("IntTexture", viewedTexture);
_renderTargetEffect.SetTexture("UIntTexture", null);
_renderTargetEffect.SetTexture("Texture", null);
}
else if (desc.Format.IsUInt())
else if (format.IsUInt())
{
// UInt Texture
_renderTargetEffect.Variables["Mode"].SetData(2);
_renderTargetEffect.SetTexture("IntTexture", null);
_renderTargetEffect.SetTexture("UIntTexture", viewedTexture.GetViewBinding(_groupIndex));
_renderTargetEffect.SetTexture("UIntTexture", viewedTexture);
_renderTargetEffect.SetTexture("Texture", null);
}
else
{
// Float Texture
_renderTargetEffect.Variables["Mode"].SetData(0);
_renderTargetEffect.SetTexture("IntTexture", null);
_renderTargetEffect.SetTexture("UIntTexture", null);
_renderTargetEffect.SetTexture("Texture", viewedTexture.GetViewBinding(_groupIndex));
_renderTargetEffect.SetTexture("Texture", viewedTexture);
}
_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
@@ -580,84 +598,15 @@ class TexturererViewerer
Quad.Draw();
}
private void RenderTexture(RenderTargetGroup viewedTexture)
{
var desc = _groupIndex >= 0 ? viewedTexture.[Friend]_colorTargetDescriptions[_groupIndex] : viewedTexture.[Friend]_depthTargetDescription;
RenderTexture(viewedTexture.GetViewBinding(_groupIndex), float2(viewedTexture.Width, viewedTexture.Height), desc.Format.GetShaderViewFormat());
}
private void RenderTexture(Texture viewedTexture)
{
Viewport vp = .(0, 0, _target.Width, _target.Height);
RenderCommand.SetViewport(vp);
// TODO: don't clear pink!
RenderCommand.Clear(_target, .Pink);
RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
//_target.Bind();
RenderCommand.SetRenderTarget(_target);
RenderCommand.SetDepthStencilTarget(_depth);
RenderCommand.BindRenderTargets();
float2 textureSize = float2(viewedTexture.Width, viewedTexture.Height);
float2 zoomedTextureSize = textureSize * _zoom;
float2 targetSize = float2(_target.Width, _target.Height);
_effect.Variables["ColorOffset"].SetData(_colorOffset);
_effect.Variables["ColorScale"].SetData(_colorScale);
_effect.Variables["AlphaOffset"].SetData(_alphaOffset);
_effect.Variables["AlphaScale"].SetData(_alphaScale);
_camera.Left = 0;
_camera.Top = 0;
_camera.Right = targetSize.X;
_camera.Bottom = -targetSize.Y;
_camera.NearPlane = -5;
_camera.FarPlane = 5;
_camera.Update();
Renderer2D.BeginScene(_camera);
switch(_backgroundMode)
{
case .Black:
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .Black);
case .White:
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .White);
case .Pink:
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .HotPink);
case .CustomColor:
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, _backgroundColor);
case .Checkerboard:
float quadSize = 50.0f;
float2 numQuads = (targetSize / 500f) * 10f;
for(float x = 0; x < numQuads.X; x++)
{
for(float y = 0; y < numQuads.Y; y++)
{
Renderer2D.DrawQuadPivotCorner(float3(x * quadSize, -y * quadSize, 1), quadSize.XX, 0, ((x + y) % 2 == 0) ? .White : .Gray);
}
}
break;
}
Renderer2D.EndScene();
var sampler = viewedTexture.SamplerState..AddRef();
switch(_sampleMode)
{
case .Point:
viewedTexture.SamplerState = SamplerStateManager.PointClamp;
case .Linear:
viewedTexture.SamplerState = SamplerStateManager.LinearClamp;
}
Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
Renderer2D.DrawQuad(float3(_position * .(1, -1), 0), zoomedTextureSize, 0, viewedTexture);
Renderer2D.EndScene();
viewedTexture.SamplerState = sampler;
sampler.ReleaseRef();
RenderTexture(viewedTexture.GetViewBinding(), float2(viewedTexture.Width, viewedTexture.Height), viewedTexture.Format);
}
}
@@ -56,31 +56,65 @@ namespace GlitchyEngine.Renderer
public override uint32 Height => nativeDesc.Height;
public override uint32 ArraySize => nativeDesc.ArraySize;
public override uint32 MipLevels => nativeDesc.MipLevels;
public override Format Format => nativeDesc.Format;
protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
/*protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
{
Debug.Profiler.ProfileResourceFunction!();
PrepareTexturePlatform(desc, isRenderTarget);
InternalCreateTexture(data, linePitch, 0);
}
}*/
private void InternalCreateTexture(void* data, uint32 linePitch, uint32 slicePitch)
/// Creates the native texture. Initializes it, if slices is not null and has enough Entries to fill all slices.
/// @returns true if the texture has been initialized; false otherwise.
private bool InternalCreateTexture(Span<TextureSliceData> slices)
{
Debug.Profiler.ProfileResourceFunction!();
SubresourceData resData = .(data, linePitch, slicePitch);
SubresourceData[] data = null;
// If data is null, set subresourceData null
SubresourceData* resDataPtr = data == null ? null : &resData;
if (slices.Length == MipLevels * ArraySize)
{
data = scope:: SubresourceData[slices.Length];
var result = NativeDevice.CreateTexture2D(ref nativeDesc, resDataPtr, &nativeTexture);
for (int i < slices.Length)
{
TextureSliceData slice = slices[i];
data[i] = .(slice.Data, slice.LinePitch, slice.SlicePitch);
}
}
var result = NativeDevice.CreateTexture2D(ref nativeDesc, data?.Ptr, &nativeTexture);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture 2D. Error ({result.Underlying}): {result}");
result = NativeDevice.CreateShaderResourceView(nativeTexture, null, &_nativeResourceView);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture view. Error ({result.Underlying}): {result}");
// If Data is non-null the texture got initialized with data.
return (data != null);
}
/*private void InternalCreateTexture(void* data, uint32 linePitch, uint32 slicePitch)
{
Debug.Profiler.ProfileResourceFunction!();
/*SubresourceData resData = .(data, linePitch, slicePitch);
// If data is null, set subresourceData null
SubresourceData* resDataPtr = data == null ? null : &resData;*/
SubresourceData[2] resData = .(.(data, linePitch, slicePitch), .(null, 0, 0));
var result = NativeDevice.CreateTexture2D(ref nativeDesc, &resData, &nativeTexture);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture 2D. Error ({result.Underlying}): {result}");
result = NativeDevice.CreateShaderResourceView(nativeTexture, null, &_nativeResourceView);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture view. Error ({result.Underlying}): {result}");
}*/
protected override void PrepareTexturePlatform(Texture2DDesc desc, bool isRenderTarget)
{
Debug.Profiler.ProfileResourceFunction!();
@@ -96,6 +130,26 @@ namespace GlitchyEngine.Renderer
nativeDesc.BindFlags |= .RenderTarget;
}
protected override Result<void> PlatformSetData(Span<TextureSliceData> slices)
{
Debug.Profiler.ProfileResourceFunction!();
if(nativeTexture == null)
{
if (InternalCreateTexture(slices))
return .Ok;
}
Runtime.NotImplemented();
/*int index = firstArraySlice;
for (TextureSliceData slice in slices)
{
}*/
}
// TODO: Update Texture Arrays!
protected override Result<void> PlatformSetData(void* data, uint32 elementSize, uint32 destX,
uint32 destY, uint32 destWidth, uint32 destHeight, uint32 arraySlice, uint32 mipLevel, GlitchyEngine.Renderer.MapType mapType)
@@ -104,6 +158,21 @@ namespace GlitchyEngine.Renderer
if(nativeTexture == null)
{
if(destX == 0 && destY == 0 && destWidth == nativeDesc.Width && destHeight == nativeDesc.Height &&
arraySlice == 0 && mipLevel == 0 && ArraySize == 1 && MipLevels == 1)
{
TextureSliceData[1] dataSlice = .(.(data, elementSize * destWidth, elementSize * destWidth * destHeight));
// Turns out we need to initialize all slices at once or none... so... tough shit, we cant early out here.
if (InternalCreateTexture(dataSlice))
return .Ok;
}
else
{
InternalCreateTexture(null);
}
/* Old shit follows...
if(destX == 0 && destY == 0 && destWidth == nativeDesc.Width && destHeight == nativeDesc.Height)
{
// We can pass the data while creating the buffer, so we can return here.
@@ -116,6 +185,7 @@ namespace GlitchyEngine.Renderer
Log.EngineLogger.Assert(nativeDesc.Usage != .Immutable, "The entire immutable texture has to be initialized.");
InternalCreateTexture(null, 0, 0);
}
*/
}
//Log.EngineLogger.AssertDebug();
@@ -178,7 +248,7 @@ namespace GlitchyEngine.Renderer
// Make sure the destination was initialized
if(destination.nativeTexture == null)
destination.InternalCreateTexture(null, 0, 0);
destination.InternalCreateTexture(null);
using (ContextMonitor.Enter())
{
@@ -200,7 +270,7 @@ namespace GlitchyEngine.Renderer
// Make sure the destination was initialized
if(destination.nativeTexture == null)
destination.InternalCreateTexture(null, 0, 0);
destination.InternalCreateTexture(null);
uint32 arraySlices = Math.Min(ArraySize, destination.ArraySize);
uint32 mipSlices = Math.Min(MipLevels, destination.MipLevels);
@@ -234,6 +304,7 @@ namespace GlitchyEngine.Renderer
public override uint32 Height => nativeDesc.Height;
public override uint32 ArraySize => nativeDesc.ArraySize / 6;
public override uint32 MipLevels => nativeDesc.MipLevels;
public override Format Format => nativeDesc.Format;
protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
{
+134
View File
@@ -1,6 +1,139 @@
using System;
using GlitchyEngine.Core;
namespace DirectX.DXGI
{
public extension Format
{
public bool IsInt()
{
switch(this)
{
case R32G32B32A32_SInt, R32G32B32_SInt, R16G16B16A16_SInt, R32G32_SInt, R8G8B8A8_SInt, R16G16_SInt,
R32_SInt, R8G8_SInt, R16_SInt, R8_SInt:
return true;
default:
return false;
}
}
public bool IsUInt()
{
switch(this)
{
case R32G32B32A32_UInt, R32G32B32_UInt, R16G16B16A16_UInt, R32G32_UInt, R10G10B10A2_UInt, R8G8B8A8_UInt, R16G16_UInt,
R32_UInt, R8G8_UInt, R16_UInt, R8_UInt:
return true;
default:
return false;
}
}
public uint32 BitsPerPixel()
{
switch (this)
{
case .R32G32B32A32_Typeless,.R32G32B32A32_Float,.R32G32B32A32_UInt,.R32G32B32A32_SInt:
return 128;
case .R32G32B32_Typeless,.R32G32B32_Float,.R32G32B32_UInt,.R32G32B32_SInt:
return 96;
case .R16G16B16A16_Typeless,.R16G16B16A16_Float,.R16G16B16A16_UNorm,.R16G16B16A16_UInt,.R16G16B16A16_SNorm,.R16G16B16A16_SInt,.R32G32_Typeless,.R32G32_Float,.R32G32_UInt,.R32G32_SInt,.R32G8X24_Typeless,.D32_Float_S8X24_UInt,.R32_Float_X8X24_Typeless,.X32_Typeless_G8X24_UInt,.Y416,.Y210,.Y216:
return 64;
case .R10G10B10A2_Typeless,.R10G10B10A2_UNorm,.R10G10B10A2_UInt,.R11G11B10_Float,.R8G8B8A8_Typeless,.R8G8B8A8_UNorm,.R8G8B8A8_UNorm_SRGB,.R8G8B8A8_UInt,.R8G8B8A8_SNorm,.R8G8B8A8_SInt,.R16G16_Typeless,.R16G16_Float,.R16G16_UNorm,.R16G16_UInt,.R16G16_SNorm,.R16G16_SInt,.R32_Typeless,.D32_Float,.R32_Float,.R32_UInt,.R32_SInt,.R24G8_Typeless,.D24_UNorm_S8_UInt,.R24_UNorm_X8_Typeless,.X24_Typeless_G8_UInt,.R9G9B9E5_SHAREDEXP,.R8G8_B8G8_UNorm,.G8R8_G8B8_UNorm,.B8G8R8A8_UNorm,.B8G8R8X8_UNorm,.R10G10B10_XR_BIAS_A2_UNorm,.B8G8R8A8_Typeless,.B8G8R8A8_UNorm_SRGB,.B8G8R8X8_Typeless,.B8G8R8X8_UNorm_SRGB,.AYUV,.Y410,.YUY2:
//#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
//case .R10G10B10_7E3_A2_Float,.R10G10B10_6E4_A2_Float,.R10G10B10_SNorm_A2_UNorm:
//#endif
return 32;
case .P010,.P016, .V408:
/*#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
case .V408:
#endif
#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
case .D16_UNorm_S8_UInt,.R16_UNorm_X8_Typeless,.X16_Typeless_G8_UInt:
#endif*/
return 24;
case .R8G8_Typeless,.R8G8_UNorm,.R8G8_UInt,.R8G8_SNorm,.R8G8_SInt,.R16_Typeless,.R16_Float,.D16_UNorm,.R16_UNorm,.R16_UInt,.R16_SNorm,.R16_SInt,.B5G6R5_UNorm,.B5G5R5A1_UNorm,.A8P8,.B4G4R4A4_UNORM, .P208,.V208:
/*#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
case .P208,.V208:
#endif*/
return 16;
case .NV12,.OPAQUE_420,.NV11:
return 12;
case .R8_Typeless,.R8_UNorm,.R8_UInt,.R8_SNorm,.R8_SInt,.A8_UNorm,.BC2_Typeless,.BC2_UNorm,.BC2_UNorm_SRGB,.BC3_Typeless,.BC3_UNorm,.BC3_UNorm_SRGB,.BC5_Typeless,.BC5_UNorm,.BC5_SNorm,.BC6H_Typeless,.BC6H_UF16,.BC6H_SF16,.BC7_Typeless,.BC7_UNorm,.BC7_UNorm_SRGB,.AI44,.IA44,.P8:
/*#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
case .R4G4_UNorm:
#endif*/
return 8;
case .R1_UNorm:
return 1;
case .BC1_Typeless,.BC1_UNorm,.BC1_UNorm_SRGB,.BC4_Typeless,.BC4_UNorm,.BC4_SNorm:
return 4;
//case .Unknown,.FORCE_UInt:
default:
return 0;
}
}
/// Returns the SRGB-Format for the given Format, or the Format itself, if no SRGB-variant exists.
public Format GetSRGB()
{
switch (this)
{
case .BC1_UNorm:
return .BC1_UNorm_SRGB;
case .BC2_UNorm:
return .BC2_UNorm_SRGB;
case .BC3_UNorm:
return .BC3_UNorm_SRGB;
case .BC7_UNorm:
return .BC7_UNorm_SRGB;
case .R8G8B8A8_UNorm:
return .R8G8B8A8_UNorm_SRGB;
case .B8G8R8A8_UNorm:
return .B8G8R8A8_UNorm_SRGB;
case .B8G8R8X8_UNorm:
return .B8G8R8X8_UNorm_SRGB;
default:
return this;
}
}
/// Returns the non-SRGB-Format for the given Format.
public Format GetNonSRGB()
{
switch (this)
{
case .BC1_UNorm_SRGB:
return .BC1_UNorm;
case .BC2_UNorm_SRGB:
return .BC2_UNorm;
case .BC3_UNorm_SRGB:
return .BC3_UNorm;
case .BC7_UNorm_SRGB:
return .BC7_UNorm;
case .R8G8B8A8_UNorm_SRGB:
return .R8G8B8A8_UNorm;
case .B8G8R8A8_UNorm_SRGB:
return .B8G8R8A8_UNorm;
case .B8G8R8X8_UNorm_SRGB:
return .B8G8R8X8_UNorm;
default:
return this;
}
}
}
}
namespace GlitchyEngine.Renderer
{
/**
@@ -29,6 +162,7 @@ namespace GlitchyEngine.Renderer
typealias Format = DirectX.DXGI.Format;
public struct BufferDescription
{
/**
@@ -48,6 +48,7 @@ namespace GlitchyEngine.Renderer
public override uint32 Depth => 1;
public override uint32 ArraySize => _description.ArraySize;
public override uint32 MipLevels => _description.MipLevels;
public override Format Format => _description.PixelFormat;
protected internal DepthStencilTarget _depthStenilTarget ~ _?.ReleaseRef();
+3 -1
View File
@@ -368,7 +368,9 @@ namespace GlitchyEngine.Renderer
s_whiteTexture = new Texture2D(tex2Ddesc);
Color color = .White;
s_whiteTexture.SetData(&color);
TextureSliceData[1] data = .(.(&color, sizeof(Color), sizeof(Color)));
s_whiteTexture.SetData(data);
// Create the default sampler for the white texture
SamplerState sampler = SamplerStateManager.GetSampler(SamplerStateDescription());
+31 -2
View File
@@ -29,6 +29,8 @@ namespace GlitchyEngine.Renderer
public abstract uint32 ArraySize {get;}
public abstract uint32 MipLevels {get;}
public abstract Format Format {get;}
public abstract TextureViewBinding GetViewBinding();
}
@@ -56,6 +58,22 @@ namespace GlitchyEngine.Renderer
}
}
/// Represents the Data of one Texture Slice (a specific mip-level of a array-slice of the texture)
/// @remarks Basically works like described here: https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ns-d3d11-d3d11_subresource_data
public struct TextureSliceData
{
public void* Data;
public uint32 LinePitch;
public uint32 SlicePitch;
public this(void* data, uint32 linePitch, uint32 slicePitch)
{
Data = data;
LinePitch = linePitch;
SlicePitch = slicePitch;
}
}
public class Texture2D : Texture
{
//public override extern uint32 Width {get;}
@@ -69,6 +87,17 @@ namespace GlitchyEngine.Renderer
PrepareTexturePlatform(desc, false);
}
public Result<void> SetData(Span<TextureSliceData> slices)
{
if (slices.Length != ArraySize * MipLevels)
{
Log.EngineLogger.Error("Not enough slices provided to initialize texture.");
return .Err;
}
return PlatformSetData(slices);
}
public void SetData<T>(T* data, uint32 arraySlice = 0, uint32 mipSlice = 0)
{
PlatformSetData(data, (.)sizeof(T), 0, 0, Width, Height, arraySlice, mipSlice, .Write);
@@ -84,8 +113,6 @@ namespace GlitchyEngine.Renderer
uint32 mipLevels = 1, uint32 arraySize = 1, Usage usage = .Default, CPUAccessFlags cpuAccess = .None
*/
protected extern void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch);
/**
* Prepares the texture so that a call to SetData can successfully upload the data to the gpu.
*/
@@ -94,6 +121,8 @@ namespace GlitchyEngine.Renderer
protected extern Result<void> PlatformSetData(void* data, uint32 elementSize, uint32 destX,
uint32 destY, uint32 destWidth, uint32 destHeight, uint32 arraySlice, uint32 mipLevel, GlitchyEngine.Renderer.MapType mapType);
protected extern Result<void> PlatformSetData(Span<TextureSliceData> slices);
/**
* Copies the texel-data of this texture to the given destination texture.
*/