diff --git a/GlitchyEditor/content/Textures/test_skybox.dds b/GlitchyEditor/content/Textures/test_skybox.dds new file mode 100644 index 0000000..8e510e9 Binary files /dev/null and b/GlitchyEditor/content/Textures/test_skybox.dds differ diff --git a/GlitchyEditor/content/Textures/test_skybox.dds.ass b/GlitchyEditor/content/Textures/test_skybox.dds.ass new file mode 100644 index 0000000..2f2df14 --- /dev/null +++ b/GlitchyEditor/content/Textures/test_skybox.dds.ass @@ -0,0 +1,24 @@ +{ + AssetLoader = "EditorTextureAssetLoader", + Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){ + _isSrgb = true, + _samplerStateDescription = { + MinFilter = .Linear, + MagFilter = .Linear, + MipFilter = .Linear, + ComparisonFunction = .Never, + AddressModeU = .Clamp, + AddressModeV = .Clamp, + AddressModeW = .Clamp, + MipMinLOD = -Infinity, + MipMaxLOD = Infinity, + MaxAnisotropy = 1, + BorderColor = { + R = 1, + G = 1, + B = 1, + A = 1 + } + } + } +} \ No newline at end of file diff --git a/GlitchyEditor/src/Assets/Importers/DdsImporter.bf b/GlitchyEditor/src/Assets/Importers/DdsImporter.bf new file mode 100644 index 0000000..51d5ea4 --- /dev/null +++ b/GlitchyEditor/src/Assets/Importers/DdsImporter.bf @@ -0,0 +1,526 @@ +using System.IO; +using System; +using GlitchyEngine; +using System.Collections; + +namespace GlitchyEditor.Assets.Importers; + +// Based on https://github.com/Diron-P/DDSReader/blob/main/dds_loader.h + +public struct LoadedSurface +{ + public Span Data; + public uint32 Pitch; + public uint32 SlicePitch; + + public int ArrayIndex; + public int CubeFace; + public int MipLevel; +} + +public struct LoadedTextureInfo +{ + public enum Dimension + { + Unknown, + Texture1D, + Texture2D, + Texture3D + } + + public uint8[] PixelData = null; + public DirectX.DXGI.Format PixelFormat = .Unknown; + public int MipMapCount = 0; + public int ArraySize = 0; + public Dimension Dimension = .Unknown; + public bool IsCubeMap; + + public int Width; + public int Height; + public int Depth; +} + +static class DdsImporter +{ + private const uint32 MagicWord = 0x20534444; // 'DDS + + public enum LoadError + { + Unknown, + WrongMagicWord, + StreamReadFailed + } + + private enum HeaderFlags : uint32 + { + /// Required in every .dds file. + DDSD_CAPS = 0x1, + /// Required in every .dds file. + DDSD_HEIGHT = 0x2, + /// Required in every .dds file. + DDSD_WIDTH = 0x4, + /// Required in every .dds file. + DDSD_PITCH = 0x8, + /// Required in every .dds file. + DDSD_PIXELFORMAT = 0x1000, + /// Required in a mipmapped texture. + DDSD_MIPMAPCOUNT = 0x20000, + /// Required when pitch is provided for a compressed texture. + DDSD_LINEARSIZE = 0x80000, + /// Required in a depth texture. + DDSD_DEPTH = 0x800000 + } + + private enum Caps1 : uint32 + { + /// Should be set, when the file contains multiple surfaces (e.g. Cubemaps or Mipmaps). + Complex = 0x8, + /// Should be set, if the file contains mipmaps. + MipMap = 0x400000, + /// Should always be set. + Texture = 0x1000 + } + + [AllowDuplicates] + private enum Caps2 : uint32 + { + Cubemap = 0x200, + Cubemap_PositiveX = 0x400, + Cubemap_NegativeX = 0x800, + Cubemap_X = Cubemap_PositiveX | Cubemap_NegativeX, + Cubemap_PositiveY = 0x1000, + Cubemap_NegativeY = 0x2000, + Cubemap_Y = Cubemap_PositiveY | Cubemap_NegativeY, + Cubemap_PositiveZ = 0x4000, + Cubemap_NegativeZ = 0x8000, + Cubemap_Z = Cubemap_PositiveZ | Cubemap_NegativeZ, + /// This is the flag that should be set for Cubemaps in DX10+ + Cubemap_AllFaces = Cubemap | Cubemap_X | Cubemap_Y | Cubemap_Z, + + Volume = 0x200000, + } + + [CRepr] + private struct DdsHeader + { + /// Size of this structure. This member must be set to 124. + private uint32 Size; + /// Flags to indicate which members contain valid data. + public HeaderFlags Flags; + /// Surface height (in pixels). + public uint32 Height; + /// Surface width (in pixels). + public uint32 Width; + public uint32 PitchOrLinearSize; + /// Depth of a volume texture (in pixels), otherwise unused. + public uint32 Depth; + /// Number of mipmap levels, otherwise unused. + public uint32 MipMapCount; + /// Unused. + private uint32[11] Reserved1; + /// The pixel format. + public DdsPixelFormat PixelFormat; + public Caps1 Caps; + public Caps2 Caps2; + /// Unused. + private uint32 dwCaps3; + /// Unused. + private uint32 dwCaps4; + /// Unused. + private uint32 dwReserved2; + } + + private enum SurfaceType : uint32 + { + /// Texture contains alpha data; dwRGBAlphaBitMask contains valid data. + AlphaPixels = 0x1, + /// Used in some older DDS files for alpha channel only uncompressed data (dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data) + Alpha = 0x2, + + /// Texture contains compressed RGB data; dwFourCC contains valid data. + FourCC = 0x4, + /// Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks (dwRBitMask, dwGBitMask, dwBBitMask) contain valid data. + RGB = 0x40, + + RGBA = RGB | AlphaPixels, + + /// Used in some older DDS files for YUV uncompressed data (dwRGBBitCount contains the YUV bit count; + /// dwRBitMask contains the Y mask, dwGBitMask contains the U mask, dwBBitMask contains the V mask) + YUV = 0x200, + + /// Used in some older DDS files for single channel color uncompressed data (dwRGBBitCount contains the luminance channel bit count; + /// dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file. + Luminance = 0x20000 + } + + private static uint32 MakeFourCC(char8 c0, char8 c1, char8 c2, char8 c3) + { + return ((uint32)c3 << 24 | (uint32) c2 << 16 | (uint32) c1 << 8 | (uint32) c0); + } + + /*private enum FourCC : uint32 + { + DXT1 = MakeFourCC('D', 'X', 'T', '1'), + DXT2 = MakeFourCC('D', 'X', 'T', '2'), + DXT3 = MakeFourCC('D', 'X', 'T', '3'), + DXT4 = MakeFourCC('D', 'X', 'T', '4'), + DXT5 = MakeFourCC('D', 'X', 'T', '5'), + /// indicates the prescense of the DDS_HEADER_DXT10 extended header + DX10 = MakeFourCC('D', 'X', '1', '0'), + }*/ + + [CRepr] + private struct DdsPixelFormat + { + /// Structure size; set to 32 (bytes). + private uint32 Size; + /// Values which indicate what type of data is in the surface. + public SurfaceType SurfaceType; + public uint32 FourCC; + /// Number of bits in an RGB (possibly including alpha) format. Valid when dwFlags includes DDPF_RGB, DDPF_LUMINANCE, or DDPF_YUV. + public uint32 RGBBitCount; + /// Red (or luminance or Y) mask for reading color data. For instance, given the A8R8G8B8 format, the red mask would be 0x00ff0000. + public uint32 RBitMask; + /// Green (or U) mask for reading color data. For instance, given the A8R8G8B8 format, the green mask would be 0x0000ff00. + public uint32 GBitMask; + /// Blue (or V) mask for reading color data. For instance, given the A8R8G8B8 format, the blue mask would be 0x000000ff. + public uint32 BBitMask; + /// Alpha mask for reading alpha data. dwFlags must include DDPF_ALPHAPIXELS or DDPF_ALPHA. For instance, given the A8R8G8B8 format, the alpha mask would be 0xff000000. + public uint32 ABitMask; + } + + public enum ResourceDimensions : uint32 + { + Texture1D = 2, + Texture2D = 3, + Texture3D = 4 + } + + public enum MiscFlags : uint32 + { + TextureCube = 0x4, + } + + public enum AlphaMode : uint32 + { + Unknown = 0x0, + Straight = 0x1, + Premultiplied = 0x2, + Opaque = 0x3, + /// Any alpha channel content is being used as a 4th channel and is not intended to represent transparency (straight or premultiplied). + Custom = 0x4 + } + + /// DDS header extension to handle resource arrays, DXGI pixel formats that don't map to the legacy Microsoft DirectDraw pixel format structures, and additional metadata. + [CRepr] + private struct DdsDxt10Header + { + public DirectX.DXGI.Format PixelFormat; + public ResourceDimensions ResourceDimension; + public MiscFlags MiscFlags; + /// Number of elements in the array. For a 2D cubemap this is the number of cubes, so the file contains ArraySize * 6 2D textures. + /// For a 3D Texture this must be 1. + public uint32 ArraySize; + + public AlphaMode AlphaMode; + } + + private static Result DecodeHeader(Stream data, out DdsHeader header, out DdsDxt10Header? extendedHeader) + { + header = ?; + extendedHeader = null; + + // Check the magic word + Result magicWord = data.Read(); + + if (magicWord case .Err) + return .Err(.StreamReadFailed); + + if (magicWord != MagicWord) + return .Err(.WrongMagicWord); + + // Load the header + Result headerResult = data.Read(); + + if (headerResult case .Err) + return .Err(.StreamReadFailed); + + header = headerResult; + + // If available, load the extended header + if (header.PixelFormat.SurfaceType.HasFlag(.FourCC) && header.PixelFormat.FourCC == MakeFourCC('D', 'X', '1', '0')) + { + Result extendedHeaderResult = data.Read(); + + if (headerResult case .Err) + return .Err(.StreamReadFailed); + + extendedHeader = extendedHeaderResult; + } + + return .Ok; + } + + private static bool IsBitMask(DdsPixelFormat ddspf, uint32 rBitMask, uint32 gBitMask, uint32 bBitMask, uint32 aBitMask) + { + return ddspf.RBitMask == rBitMask && ddspf.GBitMask == gBitMask && ddspf.BBitMask == bBitMask && ddspf.ABitMask == aBitMask; + } + + private static DirectX.DXGI.Format GetFormat(in DdsHeader header, in DdsDxt10Header? extendedheader, bool isSrgb) + { + if (extendedheader != null) + return extendedheader.Value.PixelFormat; + + 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(.RGB)) + { + switch (pixelFormat.RGBBitCount) + { + case 32: + if (IsBitMask(pixelFormat, 0xffff, 0xffff0000, 0x0, 0x0)) + return .R16G16_UNorm; + break; + case 16: + if (IsBitMask(pixelFormat, 0xf800, 0x7e0, 0x1f, 0x0)) + return .B5G6R5_UNorm; + break; + default: + return .Unknown; + } + } + + if (pixelFormat.SurfaceType.HasFlag(.FourCC)) + { + switch (pixelFormat.FourCC) + { + case MakeFourCC('D', 'X', 'T', '1'): + return isSrgb ? .BC1_UNorm_SRGB : .BC1_UNorm; + case MakeFourCC('D', 'X', 'T', '3'): + 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('B', 'C', '4', 'U'), MakeFourCC('A', 'T', 'I', '1'): + return .BC4_UNorm; + case MakeFourCC('A', 'T', 'I', '2'): + return .BC5_UNorm; + case MakeFourCC('R', 'G', 'B', 'G'): + return .R8G8_B8G8_UNorm; + case MakeFourCC('G', 'R', 'G', 'B'): + return .G8R8_G8B8_UNorm; + case 36: + return .R16G16B16A16_UNorm; + case 111: + return .R16_Float; + case 112: + return .R16G16_Float; + case 113: + return .R16G16B16A16_Float; + case 114: + return .R32_Float; + case 115: + return .R32G32_Float; + case 116: + return .R32G32B32A32_Float; + default: + return .Unknown; + } + } + + return .Unknown; + } + + public static Result LoadDds(Stream data, bool isSrgb, List surfaces, out LoadedTextureInfo textureInfo) + { + textureInfo = .(); + + var headerResult = DecodeHeader(data, let header, let extendedHeader); + + if (headerResult case .Err) + return headerResult; + + int surfaceCount = 1; + + if (header.Flags.HasFlag(.DDSD_MIPMAPCOUNT) || header.MipMapCount != 0) + { + if (header.MipMapCount == 0) + Log.EngineLogger.Warning("Mipmap count is zero, even though the flags say it shouldn't."); + + if (!header.Flags.HasFlag(.DDSD_MIPMAPCOUNT)) + Log.EngineLogger.Warning("Mipmap count is not zero, even though the mipmap count flag isn't set."); + + textureInfo.MipMapCount = header.MipMapCount; + surfaceCount *= textureInfo.MipMapCount; + } + else + { + textureInfo.MipMapCount = 1; + } + + if (extendedHeader != null) + { + textureInfo.ArraySize = extendedHeader.Value.ArraySize; + surfaceCount *= textureInfo.ArraySize; + } + else + { + textureInfo.ArraySize = 1; + } + + if (header.Caps2.HasFlag(.Cubemap)) + { + if (!header.Caps2.HasFlag(.Cubemap_AllFaces)) + Log.EngineLogger.Warning("Texture might only contains partial cubemap, this is not allowed. (Defined Cubemap-Flag, but not all cubemap faces)"); + + surfaceCount *= 6; + textureInfo.IsCubeMap = true; + } + + textureInfo.PixelFormat = GetFormat(header, extendedHeader, isSrgb); + + textureInfo.Width = header.Width; + textureInfo.Height = header.Height; + textureInfo.Depth = header.Depth; + + switch (extendedHeader?.ResourceDimension) + { + case .Texture1D: + textureInfo.Dimension = .Texture1D; + case .Texture2D: + textureInfo.Dimension = .Texture2D; + case .Texture3D: + textureInfo.Dimension = .Texture3D; + case null: + if (header.Flags.HasFlag(.DDSD_DEPTH)) + textureInfo.Dimension = .Texture3D; + else + textureInfo.Dimension = .Texture2D; + } + + // Make sure we have enough space in the list (avoid allocations later) + surfaces.Reserve(surfaceCount); + + uint32 scanLineSize = 0; + uint32 slicePitch = 0; + uint32 numBytes = 0; + uint32 blockSize = 0; // Block size in bytes. + + switch (textureInfo.PixelFormat) + { + case .BC1_UNorm, .BC1_UNorm_SRGB, .BC4_UNorm: + blockSize = 8; + case .BC2_UNorm, .BC2_UNorm_SRGB, .BC3_UNorm, .BC3_UNorm_SRGB, .BC5_UNorm: + blockSize = 16; + default: + } + + uint32 width = 0; + uint32 height = 0; + uint32 depth = 0; + + uint32 index = 0; + + uint offset = 0; + + for (uint32 arrayIndex = 0; arrayIndex < textureInfo.ArraySize; arrayIndex++) + { + for (uint32 cubeFace = 0; cubeFace < (textureInfo.IsCubeMap ? 6 : 1); cubeFace++) + { + width = header.Width; + height = header.Height; + depth = header.Depth; + + for (uint32 mipLevel = 0; mipLevel < textureInfo.MipMapCount; ++mipLevel) + { + // This will recalculate te pitch of the main image as well. + if (header.Flags.HasFlag(.DDSD_LINEARSIZE)) + { + // compressed textures + scanLineSize = Math.Max(1, ((width + 3u) / 4u)) * blockSize; + uint32 numScanLines = Math.Max(1, ((height + 3u) / 4u)); + numBytes = scanLineSize * numScanLines; + } + else if (header.Flags.HasFlag(.DDSD_PITCH)) + { + // uncompressed data + scanLineSize = (width * header.PixelFormat.RGBBitCount + 7u) / 8u; + numBytes = scanLineSize * height; + } + + 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*)(void*)offset, numBytes); + surface.Pitch = scanLineSize; + surface.SlicePitch = slicePitch; + + surface.ArrayIndex = arrayIndex; + surface.CubeFace = cubeFace; + surface.MipLevel = mipLevel; + + surfaces.Add(surface); + + ++index; + + width >>= 1; + height >>= 1; + depth >>= 1; + + if (width == 0) + { + width = 1; + } + + if (height == 0) + { + height = 1; + } + + offset += numBytes; + } + } + } + + textureInfo.PixelData = new uint8[offset]; + + Result pixelDataResult = data.TryRead(textureInfo.PixelData); + + if (pixelDataResult case .Err) + { + delete textureInfo.PixelData; + return .Err(.StreamReadFailed); + } + + for (ref LoadedSurface surface in ref surfaces) + { + // Data pointer so far only has the offset inside the array. + // Move the pointer, so that it is inside the array. + surface.Data.Ptr += (uint)(void*)textureInfo.PixelData.Ptr; + } + + return .Ok; + } +} diff --git a/GlitchyEditor/src/Assets/MaterialAssetLoader.bf b/GlitchyEditor/src/Assets/MaterialAssetLoader.bf index c228719..4450acf 100644 --- a/GlitchyEditor/src/Assets/MaterialAssetLoader.bf +++ b/GlitchyEditor/src/Assets/MaterialAssetLoader.bf @@ -347,6 +347,7 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader for (let (slotName, textureIdentifier) in materialFile.Textures) { + AssetHandle texture = contentManager.LoadAsset(textureIdentifier); if (texture.IsInvalid) @@ -402,7 +403,7 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader for (let (slotName, texture) in material.[Friend]_textures) { - Texture textureAsset = texture.Get(); + Texture textureAsset = texture.Handle.Get(); materialFile.Textures.Add(new String(slotName), new String(textureAsset?.Identifier ?? "")); } diff --git a/GlitchyEditor/src/Assets/TextureAssetLoader.bf b/GlitchyEditor/src/Assets/TextureAssetLoader.bf index cf88063..6d5d353 100644 --- a/GlitchyEditor/src/Assets/TextureAssetLoader.bf +++ b/GlitchyEditor/src/Assets/TextureAssetLoader.bf @@ -8,6 +8,7 @@ using GlitchyEngine.Renderer; using GlitchyEngine.Math; using DirectXTK; using ImGui; +using GlitchyEditor.Assets.Importers; namespace GlitchyEditor.Assets; @@ -233,19 +234,34 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader private static Texture LoadTexture(Stream data, EditorTextureAssetLoaderConfig config) { Debug.Profiler.ProfileResourceFunction!(); + + List surfaces = scope .(); + LoadedTextureInfo textureInfo; - Texture texture = null; + // Make sure we clean up the pixel data + defer { delete textureInfo.PixelData; } + switch(GetTextureType(data)) { case .DDS: - texture = LoadDds(data, config); + Result result = LoadDds(data, config, surfaces, out textureInfo); + + if (result case .Err) + return null; + case .PNG: - texture = LoadPng(data, config); + Result result = LoadPng(data, config, surfaces, out textureInfo); + + if (result case .Err) + return null; + case .Unknown: Log.EngineLogger.Error("Unknown texture format."); - texture = null; + return null; } + + Texture texture = CreateTexture(surfaces, textureInfo); if (texture != null) { @@ -256,9 +272,74 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader return texture; } - private static Texture2D LoadPng(Stream data, EditorTextureAssetLoaderConfig config) + private static Texture CreateTexture(List surfaces, LoadedTextureInfo textureInfo) + { + switch (textureInfo.Dimension) + { + //case .Texture1D: + case .Texture2D: + if (textureInfo.IsCubeMap) + { + Texture2DDesc staging = .(); + + staging.Width = (.)textureInfo.Width; + staging.Height = (.)textureInfo.Height; + + staging.MipLevels = (.)textureInfo.MipMapCount; + staging.ArraySize = (.)textureInfo.ArraySize; + + staging.Format = textureInfo.PixelFormat; + + // TODO: allow enabling read/write + staging.CpuAccess = .None; + staging.Usage = .Default; + + TextureCube cubeTexture = new TextureCube(staging); + + for (let surface in surfaces) + { + cubeTexture.SetData(surface.Data.Ptr, surface.Pitch / staging.Width, (TextureCubeFace)surface.CubeFace, (.)surface.ArrayIndex, (.)surface.MipLevel); + } + + return cubeTexture; + } + else + { + Texture2DDesc staging = .(); + + staging.Width = (.)textureInfo.Width; + staging.Height = (.)textureInfo.Height; + + staging.MipLevels = (.)textureInfo.MipMapCount; + staging.ArraySize = (.)textureInfo.ArraySize; + + staging.Format = textureInfo.PixelFormat; + + // TODO: allow enabling read/write + staging.CpuAccess = .None; + staging.Usage = .Default; + + Texture2D stagingTexture = new Texture2D(staging); + + 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; + } + default: + Runtime.NotImplemented(); + } + + return null; + } + + private static Result LoadPng(Stream data, EditorTextureAssetLoaderConfig config, List surfaces, out LoadedTextureInfo textureInfo) { Debug.Profiler.ProfileResourceFunction!(); + + textureInfo = .(); uint8[] pngData = new:ScopedAlloc! uint8[data.Length]; @@ -267,7 +348,7 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader if (result case .Err(let err)) { Log.EngineLogger.Error($"Failed to read data from stream. Texture: Error: {err}"); - return null; + return .Err; } uint8* rawData = null; @@ -285,25 +366,55 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader if (errorCode != 0) { Log.EngineLogger.Error($"Failed to decode PNG file {errorCode}."); - return null; + return .Err; } } - Texture2DDesc desc = .(width, height, config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable); - Texture2D texture = new Texture2D(desc); - texture.SetData((.)rawData); + uint8[] pixelData = new uint8[4 * width * height]; + Internal.MemCpy(pixelData.Ptr, rawData, pixelData.Count); + + LoadedSurface surface = .(); + surface.Data = Span(pixelData); + surface.Pitch = 4 * width; + surface.SlicePitch = 0; + surface.ArrayIndex = 0; + surface.MipLevel = 0; + + surfaces.Add(surface); + + //Texture2DDesc desc = .(width, height, config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable); + //Texture2D texture = new Texture2D(desc); + //texture.SetData((.)rawData); // TODO: Generate mip maps - return texture; + textureInfo.PixelData = pixelData; + textureInfo.Width = width; + textureInfo.Height = height; + textureInfo.Depth = 1; + + textureInfo.ArraySize = 1; + textureInfo.MipMapCount = 1; + + textureInfo.Dimension = .Texture2D; + + textureInfo.IsCubeMap = false; + + textureInfo.PixelFormat = config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm; + + return .Ok; + + //return texture; } - private static Texture LoadDds(Stream data, EditorTextureAssetLoaderConfig config) + private static Result LoadDds(Stream data, EditorTextureAssetLoaderConfig config, List surfaces, out LoadedTextureInfo textureInfo) { - // TODO: Move the loading of Dds files here. - Texture2D texture = new [Friend]Texture2D(data); + var result = DdsImporter.LoadDds(data, config.IsSRGB, surfaces, out textureInfo); - return texture; + if (result case .Err) + return .Err; + + return .Ok; } private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config) @@ -315,12 +426,38 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader } private static Texture2D _placeholder2D; + private static TextureCube _placeholderCube; + private static Texture2D _error2D; + private static TextureCube _errorCube; public Asset GetPlaceholderAsset(Type assetType) { switch (assetType) { + case typeof(TextureCube): + if (_placeholderCube == null) + { + // TODO: immutable + Texture2DDesc desc = .(1, 1, .R8G8B8A8_UNorm, 1, 1, .Default, .None); + + _placeholderCube = new TextureCube(desc); + _placeholderCube.SamplerState = SamplerStateManager.PointWrap; + Color color = Color.Cyan; + _placeholderCube.SetData(&color, .PositiveX); + _placeholderCube.SetData(&color, .NegativeX); + _placeholderCube.SetData(&color, .PositiveY); + _placeholderCube.SetData(&color, .NegativeY); + _placeholderCube.SetData(&color, .PositiveZ); + _placeholderCube.SetData(&color, .NegativeZ); + + Content.ManageAsset(_placeholderCube); + _placeholderCube.ReleaseRef(); + + _placeholderCube.[Friend]Complete = false; + } + + return _placeholderCube; case typeof(Texture2D): fallthrough; default: @@ -347,6 +484,31 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader { switch (assetType) { + case typeof(TextureCube): + if (_placeholderCube == null) + { + // TODO: immutable + Texture2DDesc desc = .(2, 2, .R8G8B8A8_UNorm, 1, 1, .Default, .None); + + _errorCube = new TextureCube(desc); + _errorCube.SamplerState = SamplerStateManager.PointWrap; + + Color[4] color = .(Color.HotPink, Color.Black, Color.Black, Color.HotPink); + + _errorCube.SetData(&color, .PositiveX); + _errorCube.SetData(&color, .NegativeX); + _errorCube.SetData(&color, .PositiveY); + _errorCube.SetData(&color, .NegativeY); + _errorCube.SetData(&color, .PositiveZ); + _errorCube.SetData(&color, .NegativeZ); + + Content.ManageAsset(_errorCube); + _errorCube.ReleaseRef(); + + _errorCube.[Friend]Complete = false; + } + + return _placeholderCube; case typeof(Texture2D): fallthrough; default: @@ -356,7 +518,9 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader _error2D = new Texture2D(desc); _error2D.SamplerState = SamplerStateManager.PointWrap; + Color[4] color = .(Color.HotPink, Color.Black, Color.Black, Color.HotPink); + _error2D.SetData(&color); Content.ManageAsset(_error2D); diff --git a/GlitchyEngine/src/ImGui/ImGuiLayer.bf b/GlitchyEngine/src/ImGui/ImGuiLayer.bf index 6b491e6..ac1270d 100644 --- a/GlitchyEngine/src/ImGui/ImGuiLayer.bf +++ b/GlitchyEngine/src/ImGui/ImGuiLayer.bf @@ -142,7 +142,11 @@ namespace GlitchyEngine.ImGui RenderCommand.BindRenderTargets(); #if GE_GRAPHICS_DX11 - ImGuiImplDX11.RenderDrawData(ImGui.GetDrawData()); + + using (ContextMonitor.Enter()) + { + ImGuiImplDX11.RenderDrawData(ImGui.GetDrawData()); + } #endif ImGui.CleanupFrame(); diff --git a/GlitchyEngine/src/Platform/DX11/Dx11Platform.bf b/GlitchyEngine/src/Platform/DX11/Dx11Platform.bf index af40fc4..7f28066 100644 --- a/GlitchyEngine/src/Platform/DX11/Dx11Platform.bf +++ b/GlitchyEngine/src/Platform/DX11/Dx11Platform.bf @@ -8,6 +8,7 @@ using DirectX.Common; using DirectX.D3D11; using DirectX.D3D11.SDKLayers; using System.Diagnostics; +using System.Threading; namespace GlitchyEngine.Platform.DX11 { @@ -18,6 +19,8 @@ namespace GlitchyEngine.Platform.DX11 protected internal static ID3D11Device* NativeDevice; protected internal static ID3D11DeviceContext* NativeContext; + protected internal static Monitor ContextMonitor = new Monitor() ~ delete _; + #if DEBUG protected internal static ID3D11Debug* DebugDevice; #endif @@ -42,7 +45,10 @@ namespace GlitchyEngine.Platform.DX11 HResult deviceResult; { Debug.Profiler.ProfileScope!("D3D11.CreateDevice"); - deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &NativeDevice, &deviceLevel, &NativeContext); + using (ContextMonitor.Enter()) + { + deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &NativeDevice, &deviceLevel, &NativeContext); + } } Log.EngineLogger.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message({(int32)deviceResult}): {deviceResult}"); diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Buffer.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Buffer.bf index 26f4914..6f4db20 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Buffer.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Buffer.bf @@ -100,14 +100,24 @@ namespace GlitchyEngine.Renderer { case .Default: Box dataBox = .(dstByteOffset, 0, 0, dstByteOffset + byteLength, 1, 1); - NativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength); + using (ContextMonitor.Enter()) + { + NativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength); + } case .Dynamic: Log.EngineLogger.Assert(mapType == .WriteDiscard || mapType == .WriteNoOverwrite, scope $"When writing to dynamic resources the map type must be {nameof(Renderer.MapType.WriteDiscard)} or {nameof(Renderer.MapType.WriteNoOverwrite)}."); // Todo: DoNotWaitFlag MappedSubresource map = ?; - NativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map); + using (ContextMonitor.Enter()) + { + NativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map); + } Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength); - NativeContext.Unmap(nativeBuffer, 0); + + using (ContextMonitor.Enter()) + { + NativeContext.Unmap(nativeBuffer, 0); + } case .Immutable: Log.EngineLogger.Error("Can't set the data of an immutable resource."); return .Err; diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GeometryBinding.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GeometryBinding.bf index ffd373a..e1f9820 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GeometryBinding.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GeometryBinding.bf @@ -80,13 +80,16 @@ namespace GlitchyEngine.Renderer public override void Bind() { Debug.Profiler.ProfileRendererFunction!(); - - NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets); - GraphicsContext.Get().SetVertexLayout(_vertexLayout); - NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology); - - if(_indexBuffer != null) - NativeContext.InputAssembler.SetIndexBuffer(_indexBuffer.nativeBuffer, _indexBuffer.Format == .Index32Bit ? .R32_UInt : .R16_UInt, _indexByteOffset); + + using (ContextMonitor.Enter()) + { + NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets); + GraphicsContext.Get().SetVertexLayout(_vertexLayout); + NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology); + + if(_indexBuffer != null) + NativeContext.InputAssembler.SetIndexBuffer(_indexBuffer.nativeBuffer, _indexBuffer.Format == .Index32Bit ? .R32_UInt : .R16_UInt, _indexByteOffset); + } } public override void Unbind() @@ -96,12 +99,15 @@ namespace GlitchyEngine.Renderer ID3D11Buffer*[nativeBuffers.Count] nullBuffers = .(); uint32[nativeBuffers.Count] zeroStrides = .(); uint32[nativeBuffers.Count] zeroOffsets = .(); - - NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nullBuffers, &zeroStrides, &zeroOffsets); - NativeContext.InputAssembler.SetInputLayout(null); - NativeContext.InputAssembler.SetPrimitiveTopology(.Undefined); - NativeContext.InputAssembler.SetIndexBuffer(null, .R16_UNorm, 0); + using (ContextMonitor.Enter()) + { + NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nullBuffers, &zeroStrides, &zeroOffsets); + NativeContext.InputAssembler.SetInputLayout(null); + NativeContext.InputAssembler.SetPrimitiveTopology(.Undefined); + + NativeContext.InputAssembler.SetIndexBuffer(null, .R16_UNorm, 0); + } } } } diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf index 6985b6c..0775049 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf @@ -158,19 +158,28 @@ namespace GlitchyEngine.Renderer public override void BindRenderTargets() { - NativeContext.OutputMerger.SetRenderTargets(MaxRTVCount, &_renderTargets, _depthStencilTarget); + using (ContextMonitor.Enter()) + { + NativeContext.OutputMerger.SetRenderTargets(MaxRTVCount, &_renderTargets, _depthStencilTarget); + } } public override void ClearRenderTarget(RenderTarget2D renderTarget, ColorRGBA color) { - NativeContext.ClearRenderTargetView((renderTarget ?? _swapChain.BackBuffer)._nativeRenderTargetView, color); + using (ContextMonitor.Enter()) + { + NativeContext.ClearRenderTargetView((renderTarget ?? _swapChain.BackBuffer)._nativeRenderTargetView, color); + } } public override void SetVertexBuffer(uint32 slot, Buffer buffer, uint32 stride, uint32 offset = 0) { // make stride and offset mutable so that we can take their pointers. var stride, offset; - NativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset); + using (ContextMonitor.Enter()) + { + NativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset); + } } [Inline] @@ -180,8 +189,11 @@ namespace GlitchyEngine.Renderer { _currentInputLayout = _currentVertexLayout.GetNativeVertexLayout(_currentVertexShader.nativeCode); _currentInputLayout.AddRef(); - - NativeContext.InputAssembler.SetInputLayout(_currentInputLayout); + + using (ContextMonitor.Enter()) + { + NativeContext.InputAssembler.SetInputLayout(_currentInputLayout); + } } } @@ -190,7 +202,7 @@ namespace GlitchyEngine.Renderer Debug.Profiler.ProfileRendererFunction!(); BindInputLayout(); - + if (_hasVs) NativeContext.VertexShader.SetConstantBuffers(0, _vsBuffers.Count, &_vsBuffers); @@ -200,33 +212,48 @@ namespace GlitchyEngine.Renderer public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0) { - BindState(); - - NativeContext.Draw(vertexCount, startVertexIndex); + using (ContextMonitor.Enter()) + { + BindState(); + + NativeContext.Draw(vertexCount, startVertexIndex); + } } public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0) { - BindState(); - - NativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset); + using (ContextMonitor.Enter()) + { + BindState(); + + NativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset); + } } public override void DrawIndexedInstanced(uint32 indexCountPerInstance, uint32 instanceCount, uint32 startIndexLocation, int32 baseVertexLocation, uint32 startInstanceLocation) { - BindState(); - - NativeContext.DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation); + using (ContextMonitor.Enter()) + { + BindState(); + + NativeContext.DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation); + } } public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0) { - NativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset); + using (ContextMonitor.Enter()) + { + NativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset); + } } public override void SetViewports(uint32 viewportsCount, GlitchyEngine.Renderer.Viewport* viewports) { - NativeContext.Rasterizer.SetViewports(viewportsCount, (.)viewports); + using (ContextMonitor.Enter()) + { + NativeContext.Rasterizer.SetViewports(viewportsCount, (.)viewports); + } } public override void SetVertexLayout(VertexLayout vertexLayout) @@ -241,7 +268,10 @@ namespace GlitchyEngine.Renderer public override void SetPrimitiveTopology(GlitchyEngine.Renderer.PrimitiveTopology primitiveTopology) { - NativeContext.InputAssembler.SetPrimitiveTopology((DirectX.Common.PrimitiveTopology)primitiveTopology); + using (ContextMonitor.Enter()) + { + NativeContext.InputAssembler.SetPrimitiveTopology((DirectX.Common.PrimitiveTopology)primitiveTopology); + } } private uint32 _ps_FirstTexture; @@ -343,19 +373,28 @@ namespace GlitchyEngine.Renderer public override void UnbindTextures() { void** voidArray = scope void*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]*; - - NativeContext.PixelShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray); - NativeContext.VertexShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray); + + using (ContextMonitor.Enter()) + { + NativeContext.PixelShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray); + NativeContext.VertexShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray); + } } public override void BindVertexShader(VertexShader vertexShader) { - BindShaderToStage(vertexShader); + using (ContextMonitor.Enter()) + { + BindShaderToStage(vertexShader); + } } public override void BindPixelShader(PixelShader pixelShader) { - BindShaderToStage(pixelShader); + using (ContextMonitor.Enter()) + { + BindShaderToStage(pixelShader); + } } public override void BindConstantBuffer(Buffer buffer, int slot, ShaderStage stage) diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11RenderTarget.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11RenderTarget.bf index ad44bba..51a253d 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11RenderTarget.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11RenderTarget.bf @@ -443,12 +443,25 @@ namespace GlitchyEngine.Renderer uint32 srcSubResource = D3D11.CalcSubresource(mipLevel, arraySlice, _mipLevels); Box srcBox = .(x, y, arraySlice, x + width, y + height, arraySlice + 1); - - NativeContext.CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, texture, srcSubResource, &srcBox); + using (ContextMonitor.Enter()) + { + NativeContext.CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, texture, srcSubResource, &srcBox); + } + MappedSubresource subresource = ?; - result = NativeContext.Map(stagingTexture, 0, .Read, .None, &subresource); - defer NativeContext.Unmap(stagingTexture, 0); + using (ContextMonitor.Enter()) + { + result = NativeContext.Map(stagingTexture, 0, .Read, .None, &subresource); + } + + defer + { + using (ContextMonitor.Enter()) + { + NativeContext.Unmap(stagingTexture, 0); + } + } if (result != 0) return .Err; @@ -474,8 +487,11 @@ namespace GlitchyEngine.Renderer // TODO: Mips/Arrays Box srcBox = .((.)srcTopLeft.X, (.)srcTopLeft.Y, 0, (.)(srcTopLeft.X + size.X), (.)(srcTopLeft.Y + size.Y), 1); - - NativeContext.CopySubresourceRegion(dstTexture, 0, (.)dstTopLeft.X, (.)dstTopLeft.Y, 0, srcTexture, 0, &srcBox); + + using (ContextMonitor.Enter()) + { + NativeContext.CopySubresourceRegion(dstTexture, 0, (.)dstTopLeft.X, (.)dstTopLeft.Y, 0, srcTexture, 0, &srcBox); + } } } } diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11RendererAPI.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11RendererAPI.bf index 76f2c39..283a9ad 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11RendererAPI.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11RendererAPI.bf @@ -44,8 +44,11 @@ namespace GlitchyEngine.Renderer public override void Clear(RenderTarget2D renderTarget, ColorRGBA color) { Debug.Profiler.ProfileRendererFunction!(); - - NativeContext.ClearRenderTargetView(RtOrBackbuffer!(renderTarget)._nativeRenderTargetView, color); + + using (ContextMonitor.Enter()) + { + NativeContext.ClearRenderTargetView(RtOrBackbuffer!(renderTarget)._nativeRenderTargetView, color); + } } public override void Clear(DepthStencilTarget target, ClearOptions clearOptions, float depth, uint8 stencil) @@ -66,37 +69,43 @@ namespace GlitchyEngine.Renderer { flags |= .Stencil; } - - NativeContext.ClearDepthStencilView(target.nativeView, flags, depth, stencil); + + using (ContextMonitor.Enter()) + { + NativeContext.ClearDepthStencilView(target.nativeView, flags, depth, stencil); + } } private void ClearRtv(DirectX.D3D11.ID3D11RenderTargetView* rtv, ClearColor clearColor) { - switch(clearColor) + using (ContextMonitor.Enter()) { - case .Color(let color): - NativeContext.ClearRenderTargetView(rtv, color); - case .UInt(let value): -#unwarn - NativeContext.OutputMerger.SetRenderTargets(1, &rtv, null); - - using (BlendState lastBlendState = _currentBlendState..AddRef()) + switch(clearColor) { - SetBlendState(_nonblendingState); - - _clearUintFx.Variables["ClearValue"].SetData(value); - _clearUintFx.ApplyChanges(); - _clearUintFx.Bind(); + case .Color(let color): + NativeContext.ClearRenderTargetView(rtv, color); + case .UInt(let value): + #unwarn + NativeContext.OutputMerger.SetRenderTargets(1, &rtv, null); - FullscreenQuad.Draw(); + using (BlendState lastBlendState = _currentBlendState..AddRef()) + { + SetBlendState(_nonblendingState); + + _clearUintFx.Variables["ClearValue"].SetData(value); + _clearUintFx.ApplyChanges(); + _clearUintFx.Bind(); + + FullscreenQuad.Draw(); + + SetBlendState(lastBlendState); + } - SetBlendState(lastBlendState); + // Rebind the old render targets + BindRenderTargets(); + default: + Runtime.NotImplemented(); } - - // Rebind the old render targets - BindRenderTargets(); - default: - Runtime.NotImplemented(); } } @@ -143,7 +152,10 @@ namespace GlitchyEngine.Renderer clearDepth = depth ?? clearDepth; clearStencil = stencil ?? clearStencil; - NativeContext.ClearDepthStencilView(renderTarget._nativeDepthTargetView, flags, clearDepth, clearStencil); + using (ContextMonitor.Enter()) + { + NativeContext.ClearDepthStencilView(renderTarget._nativeDepthTargetView, flags, clearDepth, clearStencil); + } } } } @@ -199,7 +211,10 @@ namespace GlitchyEngine.Renderer Debug.Profiler.ProfileRendererFunction!(); SetReference!(_currentRasterizerState, rasterizerState); - NativeContext.Rasterizer.SetState(_currentRasterizerState.nativeRasterizerState); + using (ContextMonitor.Enter()) + { + NativeContext.Rasterizer.SetState(_currentRasterizerState.nativeRasterizerState); + } } private BlendState _currentBlendState ~ _?.ReleaseRef(); @@ -209,7 +224,11 @@ namespace GlitchyEngine.Renderer Debug.Profiler.ProfileRendererFunction!(); SetReference!(_currentBlendState, blendState); - NativeContext.OutputMerger.SetBlendState(_currentBlendState.nativeBlendState, blendFactor); + + using (ContextMonitor.Enter()) + { + NativeContext.OutputMerger.SetBlendState(_currentBlendState.nativeBlendState, blendFactor); + } } private DepthStencilState _currentDepthStencilState ~ _?.ReleaseRef(); @@ -219,7 +238,11 @@ namespace GlitchyEngine.Renderer Debug.Profiler.ProfileRendererFunction!(); SetReference!(_currentDepthStencilState, depthStencilState); - NativeContext.OutputMerger.SetDepthStencilState(_currentDepthStencilState.nativeDepthStencilState, stencilReference); + + using (ContextMonitor.Enter()) + { + NativeContext.OutputMerger.SetDepthStencilState(_currentDepthStencilState.nativeDepthStencilState, stencilReference); + } } public override void DrawIndexed(GeometryBinding geometry) diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11SamplerState.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11SamplerState.bf index f29bd17..09a215d 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11SamplerState.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11SamplerState.bf @@ -122,8 +122,11 @@ namespace GlitchyEngine.Renderer public override void Bind(uint32 slot) { - NativeContext.VertexShader.SetSamplers(slot, 1, &nativeSamplerState); - NativeContext.PixelShader.SetSamplers(slot, 1, &nativeSamplerState); + using (ContextMonitor.Enter()) + { + NativeContext.VertexShader.SetSamplers(slot, 1, &nativeSamplerState); + NativeContext.PixelShader.SetSamplers(slot, 1, &nativeSamplerState); + } } } } diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Shader.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Shader.bf index 44d1f5e..d123b9a 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Shader.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Shader.bf @@ -205,7 +205,30 @@ namespace GlitchyEngine.Renderer buffer.ReleaseRef(); } case .Texture: - _textures.Add(scope String(bindDesc.Name), bindDesc.BindPoint, TextureViewBinding(null, null)); + + TextureDimension texDim; + + switch (bindDesc.Dimension) + { + case .Texture1D: + texDim = .Texture1D; + case .Texture1DArray: + texDim = .Texture1DArray; + case .Texture2D: + texDim = .Texture2D; + case .Texture2DArray: + texDim = .Texture2DArray; + case .Texture3D: + texDim = .Texture3D; + case .TextureCube: + texDim = .TextureCube; + case .TextureCubeArray: + texDim = .TextureCubeArray; + default: + texDim = .Unknown; + } + + _textures.Add(scope String(bindDesc.Name), bindDesc.BindPoint, TextureViewBinding(null, null), texDim); case .Sampler: // TODO: do we have to do something for samplers? default: diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Texture.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Texture.bf index cfd3b61..8b9d555 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Texture.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Texture.bf @@ -19,43 +19,6 @@ namespace GlitchyEngine.Renderer extension Texture { protected internal ID3D11ShaderResourceView* _nativeResourceView ~ _?.Release(); - - /** \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 bool LoadDdsResourcePlatform(Stream stream, ref T* texture) where T : ID3D11Resource - { - 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}"); - } - - ((ID3D11Resource*)texture)?.Release(); - _nativeResourceView?.Release(); - - HResult loadResult = DDSTextureLoader.CreateDDSTextureFromMemory(NativeDevice, - ddsData.Ptr, (uint)ddsData.Count, (.)&texture, &_nativeResourceView); - - if(loadResult.Failed) - { - Log.EngineLogger.Error($"Failed to load texture. Error({(int)loadResult}): {loadResult}"); - - ReleaseAndNullify!(texture); - ReleaseAndNullify!(_nativeResourceView); - - return false; - } - - return true; - } } extension Texture2DDesc @@ -94,18 +57,6 @@ namespace GlitchyEngine.Renderer public override uint32 ArraySize => nativeDesc.ArraySize; public override uint32 MipLevels => nativeDesc.MipLevels; - protected override void LoadDdsPlatform(Stream stream) - { - Debug.Profiler.ProfileResourceFunction!(); - - LoadDdsResourcePlatform(stream, ref nativeTexture); - - let resType = nativeTexture.GetResourceType(); - Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture is not a 2D texture (it is {resType})."); - - nativeTexture.GetDescription(out nativeDesc); - } - protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch) { Debug.Profiler.ProfileResourceFunction!(); @@ -177,7 +128,12 @@ namespace GlitchyEngine.Renderer case .Default: Box dataBox = .(destX, destY, 0, destX + destWidth, destY + destHeight, 1); var rowPitch = elementSize * destWidth; - NativeContext.UpdateSubresource(nativeTexture, subresourceIndex, &dataBox, data, rowPitch, rowPitch * destHeight); + + using (ContextMonitor.Enter()) + { + NativeContext.UpdateSubresource(nativeTexture, subresourceIndex, &dataBox, data, rowPitch, rowPitch * destHeight); + } + case .Dynamic: Runtime.NotImplemented(); /* @@ -220,6 +176,186 @@ namespace GlitchyEngine.Renderer sourceBox.Back = 1; } + // Make sure the destination was initialized + if(destination.nativeTexture == null) + destination.InternalCreateTexture(null, 0, 0); + + using (ContextMonitor.Enter()) + { + NativeContext.CopySubresourceRegion(destination.nativeTexture, + D3D11.CalcSubresource(destMipSlice, destArraySlice, destination.MipLevels), destX, destY, 0, + source.nativeTexture, D3D11.CalcSubresource(srcMipSlice, srcArraySlice, source.MipLevels), (.)&sourceBox); + } + } + + public override void CopyTo(Texture2D destination) + { + Debug.Profiler.ProfileResourceFunction!(); + + if(nativeTexture == null) + return; + + Log.EngineLogger.AssertDebug(nativeDesc.Format == destination.nativeDesc.Format, + "Source and destination resources must have the same texel-format."); + + // Make sure the destination was initialized + if(destination.nativeTexture == null) + destination.InternalCreateTexture(null, 0, 0); + + uint32 arraySlices = Math.Min(ArraySize, destination.ArraySize); + uint32 mipSlices = Math.Min(MipLevels, destination.MipLevels); + + for(uint32 arraySlice < arraySlices) + for(uint32 mipSlice < mipSlices) + { + Box sourceBox = .(0, 0, 0, Width, Height, 1); + + using (ContextMonitor.Enter()) + { + NativeContext.CopySubresourceRegion(destination.nativeTexture, + D3D11.CalcSubresource(mipSlice, arraySlice, destination.MipLevels), 0, 0, 0, + nativeTexture, D3D11.CalcSubresource(mipSlice, arraySlice, MipLevels), (.)&sourceBox); + } + } + } + + protected override TextureViewBinding PlatformGetViewBinding() + { + return .(_nativeResourceView, _samplerState?.nativeSamplerState); + } + } + + extension TextureCube + { + protected internal ID3D11Texture2D* nativeTexture ~ _?.Release(); + protected internal NativeTex2DDesc nativeDesc; + + public override uint32 Width => nativeDesc.Width; + public override uint32 Height => nativeDesc.Height; + public override uint32 ArraySize => nativeDesc.ArraySize / 6; + public override uint32 MipLevels => nativeDesc.MipLevels; + + protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch) + { + Debug.Profiler.ProfileResourceFunction!(); + + PrepareTexturePlatform(desc, isRenderTarget); + InternalCreateTexture(data, linePitch, 0); + } + + protected override void PrepareTexturePlatform(Texture2DDesc desc, bool isRenderTarget) + { + Debug.Profiler.ProfileResourceFunction!(); + + nativeTexture?.Release(); + nativeTexture = null; + _nativeResourceView?.Release(); + _nativeResourceView = null; + + nativeDesc = (NativeTex2DDesc)desc; + // Make it a texture cube + nativeDesc.MiscFlags |= .TextureCube; + nativeDesc.ArraySize *= 6; + + if(isRenderTarget) + nativeDesc.BindFlags |= .RenderTarget; + } + + 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 = null;//data == null ? null : &resData; + + var result = NativeDevice.CreateTexture2D(ref nativeDesc, resDataPtr, &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}"); + } + + // TODO: Update Texture Arrays! + protected override Result PlatformSetData(void* data, uint32 elementSize, uint32 destX, + uint32 destY, uint32 destWidth, uint32 destHeight, uint32 arraySlice, uint32 mipLevel, GlitchyEngine.Renderer.MapType mapType) + { + Debug.Profiler.ProfileResourceFunction!(); + + if(nativeTexture == null) + { + 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. + var rowPitch = elementSize * destWidth; + InternalCreateTexture(data, rowPitch, rowPitch * destHeight); + } + else + { + // If we don't set the entire texture we need to create the texture with unknown content and set it manually + Log.EngineLogger.Assert(nativeDesc.Usage != .Immutable, "The entire immutable texture has to be initialized."); + InternalCreateTexture(null, 0, 0); + } + } + + //Log.EngineLogger.AssertDebug(); + // TODO: Debug.Assert(dstByteOffset + byteLength <= _description.Size, "The destination offset and byte length are too long for the target buffer."); + + uint32 subresourceIndex = D3D11.CalcSubresource(mipLevel, arraySlice, nativeDesc.MipLevels); + + switch(nativeDesc.Usage) + { + case .Default: + Box dataBox = .(destX, destY, 0, destX + destWidth, destY + destHeight, 1); + var rowPitch = elementSize * destWidth; + + using (ContextMonitor.Enter()) + { + NativeContext.UpdateSubresource(nativeTexture, subresourceIndex, &dataBox, data, rowPitch, rowPitch * destHeight); + } + case .Dynamic: + Runtime.NotImplemented(); + /* + Log.EngineLogger.Assert(mapType.CanWrite, "The map type has to have write access."); + // Todo: DoNotWaitFlag + MappedSubresource map = ?; + _context.nativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map); + Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength); + _context.nativeContext.Unmap(nativeBuffer, 0); + */ + case .Immutable: + Log.EngineLogger.Error("Can't set the data of an immutable resource."); + return .Err; + default: + Log.EngineLogger.Error($"Unknown resource usage: {nativeDesc.Usage}"); + return .Err; + } + + return .Ok; + } + + /*public static override void CopySubresourceRegion(Texture2D source, Texture2D destination, + ResourceBox sourceBox = default, uint32 destX = 0, uint32 destY = 0, + uint32 srcArraySlice = 0, uint32 srcMipSlice = 0, uint32 destArraySlice = 0, uint32 destMipSlice = 0) + { + Debug.Profiler.ProfileResourceFunction!(); + + Log.EngineLogger.AssertDebug(source != destination || srcArraySlice != destArraySlice + || srcMipSlice != destMipSlice, "Cannot copy from and to the same sub resource."); + + Log.EngineLogger.AssertDebug(source.nativeDesc.Format == destination.nativeDesc.Format, + "Source and destination resources must have the same texel-format."); + + var sourceBox; + + if(sourceBox.Right == 0) + { + sourceBox.Right = source.Width; + sourceBox.Bottom = source.Height; + sourceBox.Back = 1; + } + // Make sure the destination was initialized if(destination.nativeTexture == null) destination.InternalCreateTexture(null, 0, 0); @@ -255,44 +391,13 @@ namespace GlitchyEngine.Renderer D3D11.CalcSubresource(mipSlice, arraySlice, destination.MipLevels), 0, 0, 0, nativeTexture, D3D11.CalcSubresource(mipSlice, arraySlice, MipLevels), (.)&sourceBox); } - } + }*/ protected override TextureViewBinding PlatformGetViewBinding() { return .(_nativeResourceView, _samplerState?.nativeSamplerState); } } - - extension TextureCube - { - protected internal ID3D11Texture2D* nativeTexture ~ _?.Release(); - protected internal NativeTex2DDesc nativeDesc; - - public override uint32 Width => nativeDesc.Width; - public override uint32 Height => nativeDesc.Height; - public override uint32 ArraySize => nativeDesc.ArraySize / 6; - public override uint32 MipLevels => nativeDesc.MipLevels; - - protected override void LoadTexturePlatform(Stream stream) - { - Debug.Profiler.ProfileResourceFunction!(); - - LoadDdsResourcePlatform(stream, ref nativeTexture); - - let resType = nativeTexture.GetResourceType(); - Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a texture cube (it is {resType})."); - - nativeTexture.GetDescription(out nativeDesc); - - Log.EngineLogger.Assert(nativeDesc.MiscFlags.HasFlag(.TextureCube), scope $"The texture \"{_path}\" is not a texture cube."); - // TODO: load fallback texture - } - - protected override TextureViewBinding PlatformGetViewBinding() - { - return .(_nativeResourceView, _samplerState.nativeSamplerState); - } - } } #endif diff --git a/GlitchyEngine/src/Renderer/Effect.bf b/GlitchyEngine/src/Renderer/Effect.bf index 8f92c1d..ff2fd1c 100644 --- a/GlitchyEngine/src/Renderer/Effect.bf +++ b/GlitchyEngine/src/Renderer/Effect.bf @@ -104,6 +104,18 @@ public class EffectLibrary public bool Exists(String effectName) => _effects.ContainsKey(effectName); }*/ +public enum TextureDimension +{ + Unknown, + Texture1D, + Texture1DArray, + Texture2D, + Texture2DArray, + Texture3D, + TextureCube, + TextureCubeArray +} + public class Effect : Asset { internal VertexShader _vs ~ _?.ReleaseRef(); @@ -137,14 +149,16 @@ public class Effect : Asset public struct TextureEntry { public TextureViewBinding BoundTexture; + public TextureDimension TextureDimension; public ShaderTextureCollection.ResourceEntry* VsSlot; public ShaderTextureCollection.ResourceEntry* PsSlot; - public this(TextureViewBinding boundTexture, ShaderTextureCollection.ResourceEntry* vsSlot, ShaderTextureCollection.ResourceEntry* psSlot) + public this(TextureViewBinding boundTexture, TextureDimension textureDimension, ShaderTextureCollection.ResourceEntry* vsSlot, ShaderTextureCollection.ResourceEntry* psSlot) { BoundTexture = boundTexture; VsSlot = vsSlot; PsSlot = psSlot; + TextureDimension = textureDimension; } } @@ -741,7 +755,7 @@ public class Effect : Asset // Get existing entry or create new if(!_textures.TryGetValue(shaderEntry.Name, out entry)) { - entry = .(shaderEntry.BoundTexture, null, null); + entry = .(shaderEntry.BoundTexture, shaderEntry.Dimension, null, null); entry.BoundTexture.AddRef(); } diff --git a/GlitchyEngine/src/Renderer/Material.bf b/GlitchyEngine/src/Renderer/Material.bf index fa4ce87..830478d 100644 --- a/GlitchyEngine/src/Renderer/Material.bf +++ b/GlitchyEngine/src/Renderer/Material.bf @@ -14,7 +14,7 @@ public class Material : Asset private uint8[] _rawVariables ~ delete _; - private Dictionary> _textures = new .() ~ delete _; + private Dictionary Handle, TextureDimension Dimension)> _textures = new .() ~ delete _; private Dictionary _variables = new .() ~ delete _; @@ -34,7 +34,7 @@ public class Material : Asset // At best whole paths. Shouldn't be that hard to do... /*var texture = entry.BoundTexture;*/ - _textures.Add(name, .Invalid); + _textures.Add(name, (AssetHandle.Invalid, entry.TextureDimension)); } InitRawData(); @@ -66,7 +66,19 @@ public class Material : Asset for(let (name, texture) in _textures) { - _effect.SetTexture(name, texture); + switch (texture.Dimension) + { + //case .Texture1D, .Texture1DArray: + case .Texture2D, .Texture2DArray: + AssetHandle handle2D = .(texture.Handle); + _effect.SetTexture(name, handle2D); + case .TextureCube, .TextureCubeArray: + AssetHandle cubeHandle = .(texture.Handle); + _effect.SetTexture(name, cubeHandle); + //case .Texture3D: + default: + Log.EngineLogger.Error("Tryied to bind undefined texture dimension!"); + } } for(let (name, variable) in _variables) @@ -86,13 +98,27 @@ public class Material : Asset { if(_textures.TryGetValue(name, var entry)) { + /*switch (texture.Get().GetType()) + { + //case .Texture1D: + // _textures[name].Dimension = .Texture1D; + case typeof(Texture2D): + _textures[name].Dimension = .Texture2D; + case typeof(TextureCube): + _textures[name].Dimension = .TextureCube; + //case .Texture3D: + // _textures[name].Dimension = .Texture3D; + default: + _textures[name].Dimension = .Unknown; + }*/ //entry?.ReleaseRef(); - _textures[name] = texture; + _textures[name].Handle = texture; //texture?.AddRef(); } else { - Log.EngineLogger.Assert(false); + Log.EngineLogger.Error($"Material doesn't have the texture slot \"{name}\""); + //Log.EngineLogger.Assert(false); } } diff --git a/GlitchyEngine/src/Renderer/RenderTarget.bf b/GlitchyEngine/src/Renderer/RenderTarget.bf index 12bdf0a..1a31269 100644 --- a/GlitchyEngine/src/Renderer/RenderTarget.bf +++ b/GlitchyEngine/src/Renderer/RenderTarget.bf @@ -79,15 +79,6 @@ namespace GlitchyEngine.Renderer protected extern TextureViewBinding PlatformGetViewBinding(); - protected internal override void SneakySwappyTexture(Texture otherTexture) - { - Log.EngineLogger.AssertDebug(otherTexture is RenderTarget2D, "Swapping texture must be a RenderTarget2D!"); - - SamplerState = otherTexture.SamplerState; - - PlatformSneakySwappyTexture(otherTexture as RenderTarget2D); - } - protected extern void PlatformSneakySwappyTexture(RenderTarget2D otherTexture); } diff --git a/GlitchyEngine/src/Renderer/ShaderTextureCollection.bf b/GlitchyEngine/src/Renderer/ShaderTextureCollection.bf index 08a5ab7..ccdfc46 100644 --- a/GlitchyEngine/src/Renderer/ShaderTextureCollection.bf +++ b/GlitchyEngine/src/Renderer/ShaderTextureCollection.bf @@ -3,9 +3,9 @@ using System.Collections; namespace GlitchyEngine.Renderer { - public class ShaderTextureCollection : IEnumerable<(String Name, uint32 Index, TextureViewBinding BoundTexture)> + public class ShaderTextureCollection : IEnumerable<(String Name, uint32 Index, TextureViewBinding BoundTexture, TextureDimension Dimension)> { - public typealias ResourceEntry = (String Name, uint32 Index, TextureViewBinding BoundTexture); + public typealias ResourceEntry = (String Name, uint32 Index, TextureViewBinding BoundTexture, TextureDimension Dimension); List _textures ~ DeleteTextureEntries!(_); @@ -39,14 +39,14 @@ namespace GlitchyEngine.Renderer // TODO: finish implementation (like BufferCollection) - public void Add(String name, uint32 index, TextureViewBinding texture) + public void Add(String name, uint32 index, TextureViewBinding texture, TextureDimension dimension) { - Add((name, index, texture)); + Add((name, index, texture, dimension)); } public void Add(ResourceEntry entry) { - ResourceEntry copy = (new String(entry.Name), entry.Index, entry.BoundTexture); + ResourceEntry copy = (new String(entry.Name), entry.Index, entry.BoundTexture, entry.Dimension); entry.BoundTexture.AddRef(); _textures.Add(copy); diff --git a/GlitchyEngine/src/Renderer/Texture.bf b/GlitchyEngine/src/Renderer/Texture.bf index 490f735..14b8eaf 100644 --- a/GlitchyEngine/src/Renderer/Texture.bf +++ b/GlitchyEngine/src/Renderer/Texture.bf @@ -30,11 +30,6 @@ namespace GlitchyEngine.Renderer public abstract uint32 MipLevels {get;} public abstract TextureViewBinding GetViewBinding(); - - /// Very dirtily swaps the internals with the given texture. - /// TODO: Please do this differently!!!!!!!!!!!!!!!!!!!!!! - /// This is for texture hot reloading POC, I know... it's bad... - protected internal abstract void SneakySwappyTexture(Texture otherTexture); } public struct Texture2DDesc @@ -69,17 +64,6 @@ namespace GlitchyEngine.Renderer //public override extern uint32 ArraySize {get;} //public override extern uint32 MipLevels {get;} - // TODO: remove - private this(Stream data) - { - LoadDds(data); - } - - protected void LoadDds(Stream stream) - { - LoadDdsPlatform(stream); - } - public this(Texture2DDesc desc) { PrepareTexturePlatform(desc, false); @@ -100,8 +84,6 @@ namespace GlitchyEngine.Renderer uint32 mipLevels = 1, uint32 arraySize = 1, Usage usage = .Default, CPUAccessFlags cpuAccess = .None */ - protected extern void LoadDdsPlatform(Stream stream); - protected extern void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch); /** @@ -130,17 +112,16 @@ namespace GlitchyEngine.Renderer } protected extern TextureViewBinding PlatformGetViewBinding(); + } - protected internal override void SneakySwappyTexture(Texture otherTexture) - { - Log.EngineLogger.AssertDebug(otherTexture is Texture2D, "Swapping texture must be a Texture2D!"); - - SamplerState = otherTexture.SamplerState; - - PlatformSneakySwappyTexture(otherTexture as Texture2D); - } - - protected extern void PlatformSneakySwappyTexture(Texture2D otherTexture); + public enum TextureCubeFace + { + PositiveX = 0, + NegativeX = 1, + PositiveY = 2, + NegativeY = 3, + PositiveZ = 4, + NegativeZ = 5, } public class TextureCube : Texture @@ -152,24 +133,48 @@ namespace GlitchyEngine.Renderer public override uint32 Depth => 1; // public override extern uint32 ArraySize {get;} // public override extern uint32 MipLevels {get;} - - public this(String path) + + public this(Texture2DDesc desc) { - this._path = new String(path); - LoadTexture(); + PrepareTexturePlatform(desc, false); } - private void LoadTexture() + public void SetData(void* data, int elementSize, TextureCubeFace cubeFace, uint32 arraySlice = 0, uint32 mipSlice = 0) { - Debug.Profiler.ProfileResourceFunction!(); - - Stream data = Application.Get().ContentManager.GetStream(_path); - defer delete data; - - LoadTexturePlatform(data); + PlatformSetData(data, (.)elementSize, 0, 0, Width, Height, arraySlice * 6 + (uint32)cubeFace, mipSlice, .Write); } - protected extern void LoadTexturePlatform(Stream stream); + public void SetData(T* data, TextureCubeFace cubeFace, uint32 arraySlice = 0, uint32 mipSlice = 0) + { + PlatformSetData(data, (.)sizeof(T), 0, 0, Width, Height, arraySlice * 6 + (uint32)cubeFace, mipSlice, .Write); + } + + public void SetData(T* data, uint32 x, uint32 y, uint32 width, uint32 height, TextureCubeFace cubeFace, uint32 arraySlice = 0, uint32 mipSlice = 0) + { + PlatformSetData(data, (.)sizeof(T), x, y, width, height, arraySlice * 6 + (uint32)cubeFace, mipSlice, .Write); + } + + 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. + */ + protected extern void PrepareTexturePlatform(Texture2DDesc desc, bool isRenderTarget); + + protected extern Result PlatformSetData(void* data, uint32 elementSize, uint32 destX, + uint32 destY, uint32 destWidth, uint32 destHeight, uint32 arraySlice, uint32 mipLevel, GlitchyEngine.Renderer.MapType mapType); + + /** + * Copies the texel-data of this texture to the given destination texture. + */ + public static extern void CopySubresourceRegion(Texture2D source, Texture2D destination, + ResourceBox sourceBox = default, uint32 destX = 0, uint32 destY = 0, + uint32 srcArraySlice = 0, uint32 srcMipSlice = 0, uint32 destArraySlice = 0, uint32 destMipSlice = 0); + + /** + * Copies the data to the given destination. + */ + //public extern void CopyTo(TextureCube destination); public override TextureViewBinding GetViewBinding() { @@ -177,10 +182,5 @@ namespace GlitchyEngine.Renderer } protected extern TextureViewBinding PlatformGetViewBinding(); - - protected internal override void SneakySwappyTexture(Texture otherTexture) - { - Runtime.NotImplemented(); - } } }