From: Jean-Philippe Bruyère Date: Tue, 10 Sep 2019 03:02:43 +0000 (+0200) Subject: update with latest modif from old vk.net branch X-Git-Tag: v0.1.21~37 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=b0189f4d9e401a93ac3d9d5d104020ce6d43f8f2;p=jp%2Fvke.net.git update with latest modif from old vk.net branch --- diff --git a/addons/Directory.Build.props b/addons/Directory.Build.props index 0e3fb55..bce5b09 100644 --- a/addons/Directory.Build.props +++ b/addons/Directory.Build.props @@ -24,16 +24,10 @@ NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;_WITH_VKVG - - - - - - - - + + diff --git a/addons/EnvironmentPipeline/EnvironmentPipeline.cs b/addons/EnvironmentPipeline/EnvironmentPipeline.cs new file mode 100644 index 0000000..12a0df9 --- /dev/null +++ b/addons/EnvironmentPipeline/EnvironmentPipeline.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.InteropServices; +using VK; + +namespace CVKL { + public class EnvironmentCube : GraphicPipeline { + + GPUBuffer vboSkybox; + + public Image cubemap { get; private set; } + public Image lutBrdf { get; private set; } + public Image irradianceCube { get; private set; } + public Image prefilterCube { get; set; } + + public EnvironmentCube (string cubemapPath, DescriptorSet dsSkybox, PipelineLayout plLayout, Queue staggingQ, RenderPass renderPass, PipelineCache cache = null) + : base (renderPass, cache, "EnvCube pipeline") { + + using (CommandPool cmdPool = new CommandPool (staggingQ.Dev, staggingQ.index)) { + + vboSkybox = new GPUBuffer (staggingQ, cmdPool, VkBufferUsageFlags.VertexBuffer, box_vertices); + + cubemap = KTX.KTX.Load (staggingQ, cmdPool, cubemapPath, + VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, true); + cubemap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color); + cubemap.CreateSampler (VkSamplerAddressMode.ClampToEdge); + cubemap.SetName ("skybox Texture"); + cubemap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, renderPass.Samples, false); + cfg.RenderPass = renderPass; + cfg.Layout = plLayout; + cfg.AddVertexBinding (0, 3 * sizeof (float)); + cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat); + cfg.AddShader (VkShaderStageFlags.Vertex, "#CVKLEnvironment.skybox.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "#CVKLEnvironment.skybox.frag.spv"); + cfg.multisampleState.rasterizationSamples = Samples; + + layout = cfg.Layout; + + init (cfg); + + generateBRDFLUT (staggingQ, cmdPool); + generateCubemaps (staggingQ, cmdPool); + } + + } + + public void RecordDraw (CommandBuffer cmd) { + Bind (cmd); + cmd.BindVertexBuffer (vboSkybox); + cmd.Draw (36); + } + + #region skybox + + static float[] box_vertices = { + 1.0f, 1.0f,-1.0f, // +X side + 1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + + -1.0f,-1.0f,-1.0f, // +X side + -1.0f,-1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + + -1.0f, 1.0f,-1.0f, // +Y side + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f,-1.0f, + + -1.0f,-1.0f,-1.0f, // -Y side + 1.0f,-1.0f,-1.0f, + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f,-1.0f, + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + + -1.0f, 1.0f, 1.0f, // +Z side + -1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + + -1.0f,-1.0f,-1.0f, // -Z side + 1.0f, 1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + + }; + #endregion + + void generateBRDFLUT (Queue staggingQ, CommandPool cmdPool) { + const VkFormat format = VkFormat.R16g16Sfloat; + const int dim = 512; + + lutBrdf = new Image (Dev, format, VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.Sampled, + VkMemoryPropertyFlags.DeviceLocal, dim, dim); + lutBrdf.SetName ("lutBrdf"); + + lutBrdf.CreateView (); + lutBrdf.CreateSampler (VkSamplerAddressMode.ClampToEdge); + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); + + cfg.Layout = new PipelineLayout (Dev, new DescriptorSetLayout (Dev)); + cfg.RenderPass = new RenderPass (Dev); + cfg.RenderPass.AddAttachment (format, VkImageLayout.ShaderReadOnlyOptimal); + cfg.RenderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0, 0, 0) }); + cfg.RenderPass.AddSubpass (new SubPass (VkImageLayout.ColorAttachmentOptimal)); + cfg.AddShader (VkShaderStageFlags.Vertex, "#CVKLEnvironment.genbrdflut.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "#CVKLEnvironment.genbrdflut.frag.spv"); + + using (GraphicPipeline pl = new GraphicPipeline (cfg)) { + using (Framebuffer fb = new Framebuffer (cfg.RenderPass, dim, dim, lutBrdf)) { + CommandBuffer cmd = cmdPool.AllocateCommandBuffer (); + cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit); + pl.RenderPass.Begin (cmd, fb); + cmd.SetViewport (dim, dim); + cmd.SetScissor (dim, dim); + pl.Bind (cmd); + cmd.Draw (3, 1, 0, 0); + pl.RenderPass.End (cmd); + cmd.End (); + + staggingQ.Submit (cmd); + staggingQ.WaitIdle (); + + cmd.Free (); + } + } + lutBrdf.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + } + + public enum CBTarget { IRRADIANCE = 0, PREFILTEREDENV = 1 }; + + public Image generateCubeMap (Queue staggingQ, CommandPool cmdPool, CBTarget target) { + const float deltaPhi = (2.0f * (float)Math.PI) / 180.0f; + const float deltaTheta = (0.5f * (float)Math.PI) / 64.0f; + + VkFormat format = VkFormat.R32g32b32a32Sfloat; + uint dim = 64; + + if (target == CBTarget.PREFILTEREDENV) { + format = VkFormat.R16g16b16a16Sfloat; + dim = 512; + } + + uint numMips = (uint)Math.Floor (Math.Log (dim, 2)) + 1; + + Image imgFbOffscreen = new Image (Dev, format, VkImageUsageFlags.TransferSrc | VkImageUsageFlags.ColorAttachment, + VkMemoryPropertyFlags.DeviceLocal, dim, dim); + imgFbOffscreen.SetName ("offscreenfb"); + imgFbOffscreen.CreateView (); + + Image cmap = new Image (Dev, format, VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled, + VkMemoryPropertyFlags.DeviceLocal, dim, dim, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal, + numMips, 6, 1, VkImageCreateFlags.CubeCompatible); + if (target == CBTarget.PREFILTEREDENV) + cmap.SetName ("prefilterenvmap"); + else + cmap.SetName ("irradianceCube"); + cmap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color, 6, 0); + cmap.CreateSampler (VkSamplerAddressMode.ClampToEdge); + + DescriptorPool dsPool = new DescriptorPool (Dev, 2, new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler)); + + DescriptorSetLayout dsLayout = new DescriptorSetLayout (Dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)); + + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); + cfg.Layout = new PipelineLayout (Dev, dsLayout); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf () + 8)); + + cfg.RenderPass = new RenderPass (Dev); + cfg.RenderPass.AddAttachment (format, VkImageLayout.ColorAttachmentOptimal); + cfg.RenderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0, 0, 0) }); + cfg.RenderPass.AddSubpass (new SubPass (VkImageLayout.ColorAttachmentOptimal)); + + cfg.AddVertexBinding (0, 3 * sizeof (float)); + cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat); + + cfg.AddShader (VkShaderStageFlags.Vertex, "#CVKLEnvironment.filtercube.vert.spv"); + if (target == CBTarget.PREFILTEREDENV) + cfg.AddShader (VkShaderStageFlags.Fragment, "#CVKLEnvironment.prefilterenvmap.frag.spv"); + else + cfg.AddShader (VkShaderStageFlags.Fragment, "#CVKLEnvironment.irradiancecube.frag.spv"); + + Matrix4x4[] matrices = { + // POSITIVE_X + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)) * Matrix4x4.CreateRotationY(Utils.DegreesToRadians(90)), + // NEGATIVE_X + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)) * Matrix4x4.CreateRotationY(Utils.DegreesToRadians(-90)), + // POSITIVE_Y + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(-90)), + // NEGATIVE_Y + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(90)), + // POSITIVE_Z + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)), + // NEGATIVE_Z + Matrix4x4.CreateRotationZ(Utils.DegreesToRadians(180)) + }; + + VkImageSubresourceRange subRes = new VkImageSubresourceRange (VkImageAspectFlags.Color, 0, numMips, 0, 6); + + using (GraphicPipeline pl = new GraphicPipeline (cfg)) { + + DescriptorSet dset = dsPool.Allocate (dsLayout); + DescriptorSetWrites dsUpdate = new DescriptorSetWrites (dsLayout); + dsUpdate.Write (Dev, dset, cubemap.Descriptor); + Dev.WaitIdle (); + + using (Framebuffer fb = new Framebuffer (pl.RenderPass, dim, dim, imgFbOffscreen)) { + CommandBuffer cmd = cmdPool.AllocateCommandBuffer (); + cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit); + + cmap.SetLayout (cmd, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, subRes); + + float roughness = 0; + + cmd.SetScissor (dim, dim); + cmd.SetViewport ((float)(dim), (float)dim); + + for (int m = 0; m < numMips; m++) { + roughness = (float)m / ((float)numMips - 1f); + + for (int f = 0; f < 6; f++) { + pl.RenderPass.Begin (cmd, fb); + + pl.Bind (cmd); + + float viewPortSize = (float)Math.Pow (0.5, m) * dim; + cmd.SetViewport (viewPortSize, viewPortSize); + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, + matrices[f] * Matrix4x4.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (90), 1f, 0.1f, 512f)); + if (target == CBTarget.IRRADIANCE) { + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaPhi, (uint)Marshal.SizeOf ()); + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaTheta, (uint)Marshal.SizeOf () + 4); + } else { + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, roughness, (uint)Marshal.SizeOf ()); + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, 64u, (uint)Marshal.SizeOf () + 4); + } + + cmd.BindDescriptorSet (pl.Layout, dset); + cmd.BindVertexBuffer (vboSkybox); + cmd.Draw (36); + + pl.RenderPass.End (cmd); + + imgFbOffscreen.SetLayout (cmd, VkImageAspectFlags.Color, + VkImageLayout.ColorAttachmentOptimal, VkImageLayout.TransferSrcOptimal); + + VkImageCopy region = new VkImageCopy (); + region.srcSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1); + region.dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1, (uint)m, (uint)f); + region.extent = new VkExtent3D { width = (uint)viewPortSize, height = (uint)viewPortSize, depth = 1 }; + + Vk.vkCmdCopyImage (cmd.Handle, + imgFbOffscreen.Handle, VkImageLayout.TransferSrcOptimal, + cmap.Handle, VkImageLayout.TransferDstOptimal, + 1, region.Pin ()); + region.Unpin (); + + imgFbOffscreen.SetLayout (cmd, VkImageAspectFlags.Color, + VkImageLayout.TransferSrcOptimal, VkImageLayout.ColorAttachmentOptimal); + + } + } + + cmap.SetLayout (cmd, VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal, subRes); + + cmd.End (); + + staggingQ.Submit (cmd); + staggingQ.WaitIdle (); + + cmd.Free (); + } + } + cmap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + + dsLayout.Dispose (); + imgFbOffscreen.Dispose (); + dsPool.Dispose (); + + return cmap; + } + + void generateCubemaps (Queue staggingQ, CommandPool cmdPool) { + irradianceCube = generateCubeMap (staggingQ, cmdPool, CBTarget.IRRADIANCE); + prefilterCube = generateCubeMap (staggingQ, cmdPool, CBTarget.PREFILTEREDENV); + } + + protected override void Dispose (bool disposing) { + vboSkybox.Dispose (); + cubemap.Dispose (); + lutBrdf.Dispose (); + irradianceCube.Dispose (); + prefilterCube.Dispose (); + + base.Dispose (disposing); + } + } + +} diff --git a/addons/EnvironmentPipeline/EnvironmentPipeline.csproj b/addons/EnvironmentPipeline/EnvironmentPipeline.csproj new file mode 100644 index 0000000..511e55b --- /dev/null +++ b/addons/EnvironmentPipeline/EnvironmentPipeline.csproj @@ -0,0 +1,20 @@ + + + + + CVKLEnvironment + CVKLEnvironmentPipeline + 0.1.0 + CVKL Environment cube + vulkan CVKL + $(AssemblyVersion)-beta + True + False + https://github.com/jpbruyere/vk.net/blob/master/README.md + MIT + + false + true + + + diff --git a/addons/EnvironmentPipeline/shaders/filtercube.vert b/addons/EnvironmentPipeline/shaders/filtercube.vert new file mode 100644 index 0000000..1226e28 --- /dev/null +++ b/addons/EnvironmentPipeline/shaders/filtercube.vert @@ -0,0 +1,19 @@ +#version 450 + +layout (location = 0) in vec3 inPos; + +layout(push_constant) uniform PushConsts { + layout (offset = 0) mat4 mvp; +} pushConsts; + +layout (location = 0) out vec3 outUVW; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() +{ + outUVW = inPos; + gl_Position = pushConsts.mvp * vec4(inPos.xyz, 1.0); +} diff --git a/addons/EnvironmentPipeline/shaders/genbrdflut.frag b/addons/EnvironmentPipeline/shaders/genbrdflut.frag new file mode 100644 index 0000000..b6290dd --- /dev/null +++ b/addons/EnvironmentPipeline/shaders/genbrdflut.frag @@ -0,0 +1,90 @@ +#version 450 + +layout (location = 0) in vec2 inUV; +layout (location = 0) out vec4 outColor; +layout (constant_id = 0) const uint NUM_SAMPLES = 1024u; + +const float PI = 3.1415926536; + +// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ +float random(vec2 co) +{ + float a = 12.9898; + float b = 78.233; + float c = 43758.5453; + float dt= dot(co.xy ,vec2(a,b)); + float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +vec2 hammersley2d(uint i, uint N) +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + uint bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + float rdi = float(bits) * 2.3283064365386963e-10; + return vec2(float(i) /float(N), rdi); +} + +// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf +vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +{ + // Maps a 2D point to a hemisphere with spread based on roughness + float alpha = roughness * roughness; + float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + + // Tangent space + vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(up, normal)); + vec3 tangentY = normalize(cross(normal, tangentX)); + + // Convert to world Space + return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); +} + +// Geometric Shadowing function +float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness) +{ + float k = (roughness * roughness) / 2.0; + float GL = dotNL / (dotNL * (1.0 - k) + k); + float GV = dotNV / (dotNV * (1.0 - k) + k); + return GL * GV; +} + +vec2 BRDF(float NoV, float roughness) +{ + // Normal always points along z-axis for the 2D lookup + const vec3 N = vec3(0.0, 0.0, 1.0); + vec3 V = vec3(sqrt(1.0 - NoV*NoV), 0.0, NoV); + + vec2 LUT = vec2(0.0); + for(uint i = 0u; i < NUM_SAMPLES; i++) { + vec2 Xi = hammersley2d(i, NUM_SAMPLES); + vec3 H = importanceSample_GGX(Xi, roughness, N); + vec3 L = 2.0 * dot(V, H) * H - V; + + float dotNL = max(dot(N, L), 0.0); + float dotNV = max(dot(N, V), 0.0); + float dotVH = max(dot(V, H), 0.0); + float dotNH = max(dot(H, N), 0.0); + + if (dotNL > 0.0) { + float G = G_SchlicksmithGGX(dotNL, dotNV, roughness); + float G_Vis = (G * dotVH) / (dotNH * dotNV); + float Fc = pow(1.0 - dotVH, 5.0); + LUT += vec2((1.0 - Fc) * G_Vis, Fc * G_Vis); + } + } + return LUT / float(NUM_SAMPLES); +} + +void main() +{ + outColor = vec4(BRDF(inUV.s, 1.0-inUV.t), 0.0, 1.0); +} \ No newline at end of file diff --git a/addons/EnvironmentPipeline/shaders/genbrdflut.vert b/addons/EnvironmentPipeline/shaders/genbrdflut.vert new file mode 100644 index 0000000..f3dd233 --- /dev/null +++ b/addons/EnvironmentPipeline/shaders/genbrdflut.vert @@ -0,0 +1,9 @@ +#version 450 + +layout (location = 0) out vec2 outUV; + +void main() +{ + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/addons/EnvironmentPipeline/shaders/irradiancecube.frag b/addons/EnvironmentPipeline/shaders/irradiancecube.frag new file mode 100644 index 0000000..340d679 --- /dev/null +++ b/addons/EnvironmentPipeline/shaders/irradiancecube.frag @@ -0,0 +1,37 @@ +// Generates an irradiance cube from an environment map using convolution + +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 0) out vec4 outColor; +layout (binding = 0) uniform samplerCube samplerEnv; + +layout(push_constant) uniform PushConsts { + layout (offset = 64) float deltaPhi; + layout (offset = 68) float deltaTheta; +} consts; + +#define PI 3.1415926535897932384626433832795 + +void main() +{ + vec3 N = normalize(inPos); + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = normalize(cross(up, N)); + up = cross(N, right); + + const float TWO_PI = PI * 2.0; + const float HALF_PI = PI * 0.5; + + vec3 color = vec3(0.0); + uint sampleCount = 0u; + for (float phi = 0.0; phi < TWO_PI; phi += consts.deltaPhi) { + for (float theta = 0.0; theta < HALF_PI; theta += consts.deltaTheta) { + vec3 tempVec = cos(phi) * right + sin(phi) * up; + vec3 sampleVector = cos(theta) * N + sin(theta) * tempVec; + color += texture(samplerEnv, sampleVector).rgb * cos(theta) * sin(theta); + sampleCount++; + } + } + outColor = vec4(PI * color / float(sampleCount), 1.0);//texture(samplerEnv, inPos).rgba; +} diff --git a/addons/EnvironmentPipeline/shaders/prefilterenvmap.frag b/addons/EnvironmentPipeline/shaders/prefilterenvmap.frag new file mode 100644 index 0000000..ae1212e --- /dev/null +++ b/addons/EnvironmentPipeline/shaders/prefilterenvmap.frag @@ -0,0 +1,105 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 0) out vec4 outColor; + +layout (binding = 0) uniform samplerCube samplerEnv; + +layout(push_constant) uniform PushConsts { + layout (offset = 64) float roughness; + layout (offset = 68) uint numSamples; +} consts; + +const float PI = 3.1415926536; + +// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ +float random(vec2 co) +{ + float a = 12.9898; + float b = 78.233; + float c = 43758.5453; + float dt= dot(co.xy ,vec2(a,b)); + float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +vec2 hammersley2d(uint i, uint N) +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + uint bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + float rdi = float(bits) * 2.3283064365386963e-10; + return vec2(float(i) /float(N), rdi); +} + +// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf +vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +{ + // Maps a 2D point to a hemisphere with spread based on roughness + float alpha = roughness * roughness; + float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + + // Tangent space + vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(up, normal)); + vec3 tangentY = normalize(cross(normal, tangentX)); + + // Convert to world Space + return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); +} + +// Normal Distribution function +float D_GGX(float dotNH, float roughness) +{ + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); +} + +vec3 prefilterEnvMap(vec3 R, float roughness) +{ + vec3 N = R; + vec3 V = R; + vec3 color = vec3(0.0); + float totalWeight = 0.0; + float envMapDim = float(textureSize(samplerEnv, 0).s); + for(uint i = 0u; i < consts.numSamples; i++) { + vec2 Xi = hammersley2d(i, consts.numSamples); + vec3 H = importanceSample_GGX(Xi, roughness, N); + vec3 L = 2.0 * dot(V, H) * H - V; + float dotNL = clamp(dot(N, L), 0.0, 1.0); + if(dotNL > 0.0) { + // Filtering based on https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/ + + float dotNH = clamp(dot(N, H), 0.0, 1.0); + float dotVH = clamp(dot(V, H), 0.0, 1.0); + + // Probability Distribution Function + float pdf = D_GGX(dotNH, roughness) * dotNH / (4.0 * dotVH) + 0.0001; + // Slid angle of current smple + float omegaS = 1.0 / (float(consts.numSamples) * pdf); + // Solid angle of 1 pixel across all cube faces + float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim); + // Biased (+1.0) mip level for better result + float mipLevel = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f); + color += textureLod(samplerEnv, L, mipLevel).rgb * dotNL; + totalWeight += dotNL; + + } + } + return (color / totalWeight); +} + + +void main() +{ + vec3 N = normalize(inPos); + outColor = vec4(prefilterEnvMap(N, consts.roughness), 1.0); +} diff --git a/addons/EnvironmentPipeline/shaders/skybox.frag b/addons/EnvironmentPipeline/shaders/skybox.frag new file mode 100644 index 0000000..e505ef1 --- /dev/null +++ b/addons/EnvironmentPipeline/shaders/skybox.frag @@ -0,0 +1,12 @@ +#version 450 + +layout (binding = 2) uniform samplerCube samplerEnv; + +layout (set = 0, location = 0) in vec3 inUVW; + +layout (set = 0, location = 0) out vec4 outColor; + +void main() +{ + outColor = vec4(textureLod(samplerEnv, inUVW, 1.5).rgb, 1.0); +} \ No newline at end of file diff --git a/addons/EnvironmentPipeline/shaders/skybox.vert b/addons/EnvironmentPipeline/shaders/skybox.vert new file mode 100644 index 0000000..22e285e --- /dev/null +++ b/addons/EnvironmentPipeline/shaders/skybox.vert @@ -0,0 +1,27 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 inPos; + +layout (binding = 0) uniform UBO +{ + mat4 projection; + mat4 model; + mat4 view; +} ubo; + +layout (location = 0) out vec3 outUVW; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + outUVW = inPos; + outUVW.y = -outUVW.y; + gl_Position = ubo.projection * mat4(mat3(ubo.view)) * vec4(inPos, 1.0); +} diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index 738ae0b..b61e7bd 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -24,15 +24,9 @@ NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;_WITH_VKVG - - - - - - - - + + diff --git a/samples/DistanceFieldFontTest/Program.cs b/samples/DistanceFieldFontTest/Program.cs index 1eea932..5820a02 100644 --- a/samples/DistanceFieldFontTest/Program.cs +++ b/samples/DistanceFieldFontTest/Program.cs @@ -13,6 +13,7 @@ namespace DistanceFieldFontTest { class Program : VkWindow { static void Main (string[] args) { + SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Unorm; #if DEBUG Instance.VALIDATION = true; Instance.DEBUG_UTILS = true; @@ -26,6 +27,8 @@ namespace DistanceFieldFontTest { float rotSpeed = 0.01f, zoomSpeed = 0.01f; float rotX, rotY, rotZ = 0f, zoom = 1f; + float rotAnim = 1f; + struct Matrices { public Matrix4x4 projection; public Matrix4x4 view; @@ -62,7 +65,7 @@ namespace DistanceFieldFontTest { Program () : base () { - font = new BMFont (Utils.DataDirectory + "font.fnt"); + font = new BMFont ("../data/font.fnt"); vbo = new GPUBuffer (dev, VkBufferUsageFlags.VertexBuffer, 1024); ibo = new GPUBuffer (dev, VkBufferUsageFlags.IndexBuffer, 2048); @@ -118,6 +121,8 @@ namespace DistanceFieldFontTest { staggingVbo.Dispose (); staggingIbo.Dispose (); + + UpdateFrequency = 10; } @@ -184,6 +189,11 @@ namespace DistanceFieldFontTest { buildCommandBuffers (); rebuildBuffers = false; } + if (rotAnim < 0.000001f) + return; + rotY += rotAnim; + rotAnim *= 0.95f; + updateViewRequested = true; } void buildCommandBuffers () { @@ -244,6 +254,9 @@ namespace DistanceFieldFontTest { protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { switch (key) { + case Key.Space: + rotAnim += 0.1f; + break; case Key.F2: if (modifiers.HasFlag (Modifier.Shift)) outlineColor.W -= 0.01f; @@ -257,6 +270,7 @@ namespace DistanceFieldFontTest { } } protected override void OnResize () { + base.OnResize (); updateViewRequested = true; diff --git a/samples/Model/main.cs b/samples/Model/main.cs index 6a98629..e60810e 100644 --- a/samples/Model/main.cs +++ b/samples/Model/main.cs @@ -166,6 +166,7 @@ namespace ModelSample { } protected override void OnResize () { + base.OnResize(); if (frameBuffers != null) for (int i = 0; i < swapChain.ImageCount; ++i) diff --git a/samples/Textured/main.cs b/samples/Textured/main.cs index 6b64eed..390e217 100644 --- a/samples/Textured/main.cs +++ b/samples/Textured/main.cs @@ -219,6 +219,7 @@ namespace Textured { } protected override void OnResize () { + base.OnResize(); updateMatrices (); diff --git a/samples/TexturedCube/main.cs b/samples/TexturedCube/main.cs index 21aef33..98fd5c3 100644 --- a/samples/TexturedCube/main.cs +++ b/samples/TexturedCube/main.cs @@ -275,10 +275,10 @@ namespace TextureCube { } protected override void OnResize () { - dev.WaitIdle (); + base.OnResize (); #if WITH_VKVG - vkvgPipeline.Resize ((int)swapChain.Width, (int)swapChain.Height, new DescriptorSetWrites (dsVkvg, dsLayout.Bindings[1])); + vkvgPipeline.Resize ((int)Width, (int)Height, new DescriptorSetWrites (dsVkvg, dsLayout.Bindings[1])); #endif updateMatrices (); diff --git a/samples/Triangle/main.cs b/samples/Triangle/main.cs index 75c20ed..2dcb68f 100644 --- a/samples/Triangle/main.cs +++ b/samples/Triangle/main.cs @@ -67,10 +67,10 @@ namespace Triangle { dsLayout = new DescriptorSetLayout (dev, new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer)); - GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1); + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1,false); cfg.Layout = new PipelineLayout (dev, dsLayout); - cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), cfg.Samples); + cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, cfg.Samples); cfg.AddVertexBinding (0); cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat); @@ -141,7 +141,7 @@ namespace Triangle { } protected override void OnResize () { - dev.WaitIdle (); + base.OnResize (); if (frameBuffers != null) for (int i = 0; i < swapChain.ImageCount; ++i) @@ -152,16 +152,12 @@ namespace Triangle { frameBuffers[i] = new Framebuffer (pipeline.RenderPass, swapChain.Width, swapChain.Height, (pipeline.Samples == VkSampleCountFlags.SampleCount1) ? new Image[] { swapChain.images[i], - null } : new Image[] { - null, null, swapChain.images[i] }); buildCommandBuffers (); - - dev.WaitIdle (); } protected override void Dispose (bool disposing) { diff --git a/samples/common/CrowWin.cs b/samples/common/CrowWin.cs index 4eb8730..0a9809e 100644 --- a/samples/common/CrowWin.cs +++ b/samples/common/CrowWin.cs @@ -23,7 +23,7 @@ namespace Crow { protected Interface crow; protected vkvg.Device vkvgDev; protected CVKL.Image uiImage; - protected bool isRunning; + protected bool isRunning, rebuildBuffers; protected CrowWin (string name = "CrowWin", uint _width = 1024, uint _height = 768, bool vSync = false) : base (name, _width, _height, vSync) { diff --git a/samples/deferred/main-crow.cs b/samples/deferred/main-crow.cs index fe0fc4c..e5c5598 100644 --- a/samples/deferred/main-crow.cs +++ b/samples/deferred/main-crow.cs @@ -129,7 +129,6 @@ namespace deferred { int curModelIndex = 0; bool reloadModel; - bool rebuildBuffers; Queue transferQ; DeferredPbrRenderer renderer; diff --git a/samples/deferred/main.cs b/samples/deferred/main.cs index f15132b..8ad5dbe 100644 --- a/samples/deferred/main.cs +++ b/samples/deferred/main.cs @@ -12,7 +12,7 @@ namespace deferred { #if DEBUG Instance.VALIDATION = true; Instance.DEBUG_UTILS = true; - Instance.RENDER_DOC_CAPTURE = false; + //Instance.RENDER_DOC_CAPTURE = false; #endif SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb; DeferredPbrRenderer.TEXTURE_ARRAY = true; @@ -55,7 +55,6 @@ namespace deferred { Utils.DataDirectory + "textures/uffizi_cube.ktx", }; string[] modelPathes = { - //"/mnt/devel/gts/vkChess.net/data/models/chess.glb", Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf", Utils.DataDirectory + "models/shadow.glb", Utils.DataDirectory + "models/Hubble.glb", @@ -211,24 +210,25 @@ namespace deferred { float finalDebug = -1.0f; void buildCommandBuffers () { - cmdPbr?.Free (); - cmdPbr = cmdPool.AllocateAndStart (); - renderer.buildCommandBuffers (cmdPbr); - cmdPbr.End (); + //cmdPbr?.Free (); + //cmdPbr = cmdPool.AllocateAndStart (); + //renderer.buildCommandBuffers (cmdPbr); + //cmdPbr.End (); - cmdBlur?.Free (); - cmdBlur = computeCmdPool.AllocateAndStart (); - buildBlurCmd (cmdBlur); + //cmdBlur?.Free (); + //cmdBlur = computeCmdPool.AllocateAndStart (); + //buildBlurCmd (cmdBlur); for (int i = 0; i < swapChain.ImageCount; ++i) { cmds[i]?.Free (); cmds[i] = cmdPool.AllocateAndStart (); + renderer.buildCommandBuffers (cmds[i]); //renderer.hdrImgResolved.SetLayout (cmds[i], VkImageAspectFlags.Color, - //VkAccessFlags.TransferRead, VkAccessFlags.ShaderRead, - //VkImageLayout.TransferSrcOptimal, VkImageLayout.ShaderReadOnlyOptimal, - //VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader); + //VkAccessFlags.TransferRead, VkAccessFlags.ShaderRead, + //VkImageLayout.TransferSrcOptimal, VkImageLayout.ShaderReadOnlyOptimal, + //VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader); plToneMap.RenderPass.Begin (cmds[i], frameBuffers[i]); @@ -290,21 +290,18 @@ namespace deferred { } if (cmds[idx] == null) - return; - - presentQueue.Submit (cmdPbr, swapChain.presentComplete, renderer.DrawComplete); - - computeQ.Submit (cmdBlur, renderer.DrawComplete, blurComplete); + return; - presentQueue.Submit (cmds[idx], blurComplete, drawComplete[idx]); + presentQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx]); presentQueue.Present (swapChain, drawComplete[idx]); - - presentQueue.WaitIdle (); } + protected override void OnResize () { + base.OnResize (); + dev.WaitIdle (); - renderer.Resize (swapChain.Width, swapChain.Height); + renderer.Resize (Width, Height); UpdateView (); diff --git a/samples/pbr/main.cs b/samples/pbr/main.cs index b664c50..0a0cd35 100644 --- a/samples/pbr/main.cs +++ b/samples/pbr/main.cs @@ -247,6 +247,8 @@ namespace pbrSample { protected override void OnResize () { + base.OnResize(); + dev.WaitIdle (); #if WITH_VKVG vkvgPipeline.Resize ((int)swapChain.Width, (int)swapChain.Height, diff --git a/samples/pbr/pbr.csproj b/samples/pbr/pbr.csproj index deb35f4..acc948d 100644 --- a/samples/pbr/pbr.csproj +++ b/samples/pbr/pbr.csproj @@ -6,7 +6,7 @@ - CVKL.simpletexture.frag.spv + vke.simpletexture.frag.spv diff --git a/vke/src/MarshaledObject.cs b/vke/src/MarshaledObject.cs index 6116071..231e69a 100644 --- a/vke/src/MarshaledObject.cs +++ b/vke/src/MarshaledObject.cs @@ -1,28 +1,6 @@ -// -// MarshaledObject.cs +// Copyright (c) 2019 Jean-Philippe Bruyère // -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2019 jp -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; using System.Runtime.InteropServices; diff --git a/vke/src/MemoryPool.cs b/vke/src/MemoryPool.cs index 1c5e3ab..2fbc8d8 100644 --- a/vke/src/MemoryPool.cs +++ b/vke/src/MemoryPool.cs @@ -1,6 +1,7 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; using VK; using static VK.Vk; @@ -11,6 +12,9 @@ namespace CVKL { Random, Linear } + /// + /// A memory pool is a single chunck of memory of a kind shared among multiple resources. + /// public class MemoryPool : IDisposable { Device dev; internal VkDeviceMemory vkMemory; @@ -30,6 +34,12 @@ namespace CVKL { public IntPtr MappedData => mappedPointer; public Resource Last => lastResource; + /// + /// Initializes a new instance of the class. + /// + /// device + /// Memory type index. + /// Size public MemoryPool (Device dev, uint memoryTypeIndex, UInt64 size) { this.dev = dev; memInfo.allocationSize = size; @@ -94,10 +104,8 @@ namespace CVKL { resource.bindMemory (); } - - - public void Defrag () { - + public void Defrag () { + throw new NotImplementedException (); } public void Remove (Resource resource) { @@ -113,7 +121,6 @@ namespace CVKL { } resource.next = resource.previous = null; } - public void Map (ulong size = Vk.WholeSize, ulong offset = 0) { Utils.CheckResult (vkMapMemory (dev.VkDev, vkMemory, offset, size, 0, ref mappedPointer)); } @@ -127,8 +134,11 @@ namespace CVKL { protected virtual void Dispose (bool disposing) { if (!disposedValue) { - if (!disposing) + if (disposing) { + //TODO:should automatically free resources here + } else System.Diagnostics.Debug.WriteLine ("MemoryPool disposed by Finalizer."); + vkFreeMemory (dev.VkDev, vkMemory, IntPtr.Zero); disposedValue = true; } diff --git a/vke/src/ResourceManager.cs b/vke/src/ResourceManager.cs index e450754..c6bbd22 100644 --- a/vke/src/ResourceManager.cs +++ b/vke/src/ResourceManager.cs @@ -1,21 +1,22 @@ using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; using VK; -using static VK.Vk; - namespace CVKL { #if MEMORY_POOLS + /// + /// Resource manager is responsible for the memory allocations. It holds one pool for each memory type + /// public class ResourceManager : IDisposable { VkPhysicalDeviceMemoryProperties memoryProperties; public MemoryPool[] memoryPools; ulong[] reservedHeapMemory; VkMemoryHeap getHeapFromMemoryIndex (uint i) => memoryProperties.memoryHeaps[memoryProperties.memoryTypes[i].heapIndex]; - - + /// + /// Create a new resource manager that will create one memory pool for each kind of memory available on the device + /// + /// Device + /// part of the whole available memory size to reserve by pools public ResourceManager (Device dev, ulong defaultPoolsBlockDivisor = 4) { memoryProperties = dev.phy.memoryProperties; memoryPools = new MemoryPool[memoryProperties.memoryTypeCount]; @@ -27,7 +28,10 @@ namespace CVKL { reservedHeapMemory[memoryProperties.memoryTypes[i].heapIndex] += size; } } - + /// + /// Add one or more resources to the manager, pool will be choosen depending on the resource memory flags + /// + /// Resource(s). public void Add (params Resource[] resources) { foreach (Resource res in resources) { res.updateMemoryRequirements (); @@ -46,7 +50,9 @@ namespace CVKL { } throw new InvalidOperationException ("Could not find a suitable memory type!"); } - + /// + /// Dispose all memory pools held by this resource manager. + /// public void Dispose () { for (uint i = 0; i < memoryPools.Length; i++) memoryPools[i].Dispose (); diff --git a/vke/src/ShaderInfo.cs b/vke/src/ShaderInfo.cs index f523f06..1058830 100644 --- a/vke/src/ShaderInfo.cs +++ b/vke/src/ShaderInfo.cs @@ -5,6 +5,9 @@ using System; using VK; namespace CVKL { + /// + /// This class is a helper class for VkPipelineShaderStageCreateInfo creation. + /// public class ShaderInfo : IDisposable { public VkShaderStageFlags StageFlags; public string SpirvPath; @@ -15,9 +18,11 @@ namespace CVKL { StageFlags = _stageFlags; SpirvPath = _spirvPath; EntryPoint = new FixedUtf8String (_entryPoint); - this.SpecializationInfo = specializationInfo; + SpecializationInfo = specializationInfo; } - + /// + /// Create the VkPipelineShaderStageCreateInfo structure. Note that the ShaderModule is created here and has to be destroy after the pipeline creation + /// public VkPipelineShaderStageCreateInfo GetStageCreateInfo (Device dev) { return new VkPipelineShaderStageCreateInfo { sType = VkStructureType.PipelineShaderStageCreateInfo, @@ -33,9 +38,9 @@ namespace CVKL { protected virtual void Dispose (bool disposing) { if (!disposedValue) { - if (disposing) + if (disposing) { EntryPoint.Dispose (); - + } disposedValue = true; } } diff --git a/vke/src/VkWindow.cs b/vke/src/VkWindow.cs index 6f5d9e4..3207574 100644 --- a/vke/src/VkWindow.cs +++ b/vke/src/VkWindow.cs @@ -2,6 +2,7 @@ // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Glfw; @@ -14,7 +15,7 @@ namespace CVKL { /// Provide default swapchain with its command pool and buffers per image and the main present queue /// public abstract class VkWindow : IDisposable { - static VkWindow currentWindow; + static Dictionary windows = new Dictionary(); IntPtr hWin; @@ -40,7 +41,6 @@ namespace CVKL { /// protected Camera camera = new Camera (Utils.DegreesToRadians (45f), 1f); - uint width, height; bool[] buttons = new bool[10]; public Modifier KeyModifiers = 0; @@ -57,21 +57,25 @@ namespace CVKL { /// public long UpdateFrequency = 200; - public uint Width => width; - public uint Height => height; + public uint Width { get; private set; } + public uint Height { get; private set; } + public string Title { + set { + Glfw3.SetWindowTitle (hWin, value); + } + } public VkWindow (string name = "VkWindow", uint _width = 800, uint _height = 600, bool vSync = false) { - currentWindow = this; - width = _width; - height = _height; + Width = _width; + Height = _height; Glfw3.Init (); Glfw3.WindowHint (WindowAttribute.ClientApi, 0); Glfw3.WindowHint (WindowAttribute.Resizable, 1); - hWin = Glfw3.CreateWindow ((int)width, (int)height, name, MonitorHandle.Zero, IntPtr.Zero); + hWin = Glfw3.CreateWindow ((int)Width, (int)Height, name, MonitorHandle.Zero, IntPtr.Zero); if (hWin == IntPtr.Zero) throw new Exception ("[GLFW3] Unable to create vulkan Window"); @@ -83,6 +87,8 @@ namespace CVKL { Glfw3.SetScrollCallback (hWin, HandleScrollDelegate); Glfw3.SetCharCallback (hWin, HandleCharDelegate); + windows.Add (hWin, this); + initVulkan (vSync); } IntPtr currentCursor; @@ -120,21 +126,24 @@ namespace CVKL { //activate the device to have effective queues created accordingly to what's available dev.Activate (enabledFeatures, EnabledDeviceExtensions); - swapChain = new SwapChain (presentQueue as PresentQueue, width, height, SwapChain.PREFERED_FORMAT, + swapChain = new SwapChain (presentQueue as PresentQueue, Width, Height, SwapChain.PREFERED_FORMAT, vSync ? VkPresentModeKHR.FifoKHR : VkPresentModeKHR.MailboxKHR); swapChain.Create (); + Width = swapChain.Width; + Height = swapChain.Height; + cmdPool = new CommandPool (dev, presentQueue.qFamIndex); cmds = new CommandBuffer[swapChain.ImageCount]; drawComplete = new VkSemaphore[swapChain.ImageCount]; - for (int i = 0; i < swapChain.ImageCount; i++) + for (int i = 0; i < swapChain.ImageCount; i++) { drawComplete[i] = dev.CreateSemaphore (); + drawComplete[i].SetDebugMarkerName (dev, "Semaphore DrawComplete" + i); + } cmdPool.SetName ("main CmdPool"); - for (int i = 0; i < swapChain.ImageCount; i++) - drawComplete[i].SetDebugMarkerName (dev, "Semaphore DrawComplete" + i); } /// /// override this method to modify enabled features before device creation @@ -188,10 +197,10 @@ namespace CVKL { switch (key) { case Key.F4: if (modifiers == Modifier.Alt) - Glfw3.SetWindowShouldClose (currentWindow.hWin, 1); + Glfw3.SetWindowShouldClose (hWin, 1); break; case Key.Escape: - Glfw3.SetWindowShouldClose (currentWindow.hWin, 1); + Glfw3.SetWindowShouldClose (hWin, 1); break; case Key.Up: camera.Move (0, 0, 1); @@ -226,32 +235,32 @@ namespace CVKL { #region events delegates static void HandleWindowSizeDelegate (IntPtr window, int width, int height) { } static void HandleCursorPosDelegate (IntPtr window, double xPosition, double yPosition) { - currentWindow.onMouseMove (xPosition, yPosition); - currentWindow.lastMouseX = xPosition; - currentWindow.lastMouseY = yPosition; + windows[window].onMouseMove (xPosition, yPosition); + windows[window].lastMouseX = xPosition; + windows[window].lastMouseY = yPosition; } static void HandleMouseButtonDelegate (IntPtr window, Glfw.MouseButton button, InputAction action, Modifier mods) { if (action == InputAction.Press) { - currentWindow.buttons[(int)button] = true; - currentWindow.onMouseButtonDown (button); + windows[window].buttons[(int)button] = true; + windows[window].onMouseButtonDown (button); } else { - currentWindow.buttons[(int)button] = false; - currentWindow.onMouseButtonUp (button); + windows[window].buttons[(int)button] = false; + windows[window].onMouseButtonUp (button); } } static void HandleScrollDelegate (IntPtr window, double xOffset, double yOffset) { - currentWindow.onScroll (xOffset, yOffset); + windows[window].onScroll (xOffset, yOffset); } static void HandleKeyDelegate (IntPtr window, Key key, int scanCode, InputAction action, Modifier modifiers) { - currentWindow.KeyModifiers = modifiers; + windows[window].KeyModifiers = modifiers; if (action == InputAction.Press || action == InputAction.Repeat) { - currentWindow.onKeyDown (key, scanCode, modifiers); + windows[window].onKeyDown (key, scanCode, modifiers); } else { - currentWindow.onKeyUp (key, scanCode, modifiers); + windows[window].onKeyUp (key, scanCode, modifiers); } } static void HandleCharDelegate (IntPtr window, CodePoint codepoint) { - currentWindow.onChar (codepoint); + windows[window].onChar (codepoint); } #endregion @@ -296,9 +305,13 @@ namespace CVKL { public virtual void Update () { } /// - /// called when swapchain has been resized, override this method to resize your framebuffers coupled to the swapchain + /// called when swapchain has been resized, override this method to resize your framebuffers coupled to the swapchain. + /// The base method will update Window width and height with new swapchain's dimensions. /// - protected virtual void OnResize () { } + protected virtual void OnResize () { + Width = swapChain.Width; + Height = swapChain.Height; + } #region IDisposable Support diff --git a/vke/src/base/Device.cs b/vke/src/base/Device.cs index 1bb9e09..299b288 100644 --- a/vke/src/base/Device.cs +++ b/vke/src/base/Device.cs @@ -133,6 +133,7 @@ namespace CVKL { } public void DestroySemaphore (VkSemaphore semaphore) { vkDestroySemaphore (dev, semaphore, IntPtr.Zero); + semaphore = 0; } public VkFence CreateFence (bool signaled = false) { VkFence tmp; @@ -141,8 +142,11 @@ namespace CVKL { Utils.CheckResult (vkCreateFence (dev, ref info, IntPtr.Zero, out tmp)); return tmp; } + /// Destroy the fence. + /// A valid fence handle. public void DestroyFence (VkFence fence) { vkDestroyFence (dev, fence, IntPtr.Zero); + fence = 0; } public void WaitForFence (VkFence fence, ulong timeOut = UInt64.MaxValue) { vkWaitForFences (dev, 1, ref fence, 1, timeOut); @@ -161,6 +165,7 @@ namespace CVKL { public void DestroyShaderModule (VkShaderModule module) { vkDestroyShaderModule (VkDev, module, IntPtr.Zero); + module = 0; } public void WaitIdle () { Utils.CheckResult (vkDeviceWaitIdle (dev)); diff --git a/vke/src/base/Queue.cs b/vke/src/base/Queue.cs index b463ba6..93444ae 100644 --- a/vke/src/base/Queue.cs +++ b/vke/src/base/Queue.cs @@ -65,7 +65,7 @@ namespace CVKL { VkPresentInfoKHR present = VkPresentInfoKHR.New(); uint idx = swapChain.currentImageIndex; - VkSwapchainKHR sc = swapChain.handle; + VkSwapchainKHR sc = swapChain.Handle; present.swapchainCount = 1; present.pSwapchains = sc.Pin(); present.waitSemaphoreCount = 1; diff --git a/vke/src/base/RenderPass.cs b/vke/src/base/RenderPass.cs index 1609f56..c5662f9 100644 --- a/vke/src/base/RenderPass.cs +++ b/vke/src/base/RenderPass.cs @@ -57,7 +57,7 @@ namespace CVKL { Samples = samples; AddAttachment (colorFormat, (samples == VkSampleCountFlags.SampleCount1) ? VkImageLayout.PresentSrcKHR : VkImageLayout.ColorAttachmentOptimal, samples, - loadOp, VkAttachmentStoreOp.Store, VkImageLayout.Undefined); + loadOp, VkAttachmentStoreOp.Store); ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); SubPass subpass0 = new SubPass (); @@ -73,10 +73,10 @@ namespace CVKL { AddDependency (Vk.SubpassExternal, 0, VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, - VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); + VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentWrite); AddDependency (0, Vk.SubpassExternal, VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, - VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); } /// diff --git a/vke/src/base/SwapChain.cs b/vke/src/base/SwapChain.cs index 0ebdb0d..f519055 100644 --- a/vke/src/base/SwapChain.cs +++ b/vke/src/base/SwapChain.cs @@ -38,7 +38,7 @@ namespace CVKL { /// public static VkImageUsageFlags IMAGES_USAGE = VkImageUsageFlags.ColorAttachment; - internal VkSwapchainKHR handle; + public VkSwapchainKHR Handle { get; private set; } internal uint currentImageIndex; VkSwapchainCreateInfoKHR createInfos; @@ -48,11 +48,11 @@ namespace CVKL { public Image[] images; protected override VkDebugMarkerObjectNameInfoEXT DebugMarkerInfo - => new VkDebugMarkerObjectNameInfoEXT (VkDebugReportObjectTypeEXT.SwapchainKhrEXT, handle.Handle); - + => new VkDebugMarkerObjectNameInfoEXT (VkDebugReportObjectTypeEXT.SwapchainKhrEXT, Handle.Handle); + /// Swapchain images count. public uint ImageCount => (uint)images?.Length; - public uint Width => createInfos.imageExtent.width; + public uint Width => createInfos.imageExtent.width; public uint Height => createInfos.imageExtent.height; public VkFormat ColorFormat => createInfos.imageFormat; public VkImageUsageFlags ImageUsage => createInfos.imageUsage; @@ -101,7 +101,9 @@ namespace CVKL { } base.Activate (); } - + /// + /// Create swapchain and populate images array + /// public void Create () { if (state != ActivableState.Activated) Activate (); @@ -112,7 +114,7 @@ namespace CVKL { createInfos.minImageCount = capabilities.minImageCount; createInfos.preTransform = capabilities.currentTransform; - createInfos.oldSwapchain = handle; + createInfos.oldSwapchain = Handle; if (capabilities.currentExtent.width == 0xFFFFFFFF) { if (createInfos.imageExtent.width < capabilities.minImageExtent.width) @@ -128,11 +130,11 @@ namespace CVKL { createInfos.imageExtent = capabilities.currentExtent; VkSwapchainKHR newSwapChain = Dev.CreateSwapChain (createInfos); - if (handle.Handle != 0) + if (Handle.Handle != 0) _destroy (); - handle = newSwapChain; + Handle = newSwapChain; - VkImage[] tmp = Dev.GetSwapChainImages (handle); + VkImage[] tmp = Dev.GetSwapChainImages (Handle); images = new Image[tmp.Length]; for (int i = 0; i < tmp.Length; i++) { images[i] = new Image (Dev, tmp[i], ColorFormat, ImageUsage, Width, Height); @@ -141,9 +143,13 @@ namespace CVKL { images[i].Descriptor.imageView.SetDebugMarkerName (Dev, "SwapChain Img" + i + " view"); } } - - public int GetNextImage () { - VkResult res = vkAcquireNextImageKHR (Dev.VkDev, handle, UInt64.MaxValue, presentComplete, VkFence.Null, out currentImageIndex); + /// + /// Acquire next image, recreate swapchain if out of date or suboptimal error. + /// + /// Swapchain image index or -1 if failed + /// Fence param of 'vkAcquireNextImageKHR' + public int GetNextImage (VkFence fence = default(VkFence)) { + VkResult res = vkAcquireNextImageKHR (Dev.VkDev, Handle, UInt64.MaxValue, presentComplete, fence, out currentImageIndex); if (res == VkResult.ErrorOutOfDateKHR || res == VkResult.SuboptimalKHR) { Create (); return -1; @@ -156,11 +162,11 @@ namespace CVKL { for (int i = 0; i < ImageCount; i++) images[i].Dispose (); - Dev.DestroySwapChain (handle); + Dev.DestroySwapChain (Handle); } public override string ToString () { - return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString ("x")}]"); + return string.Format ($"{base.ToString ()}[0x{Handle.Handle.ToString ("x")}]"); } #region IDisposable Support diff --git a/vke/src/glfw/CodePoint.cs b/vke/src/glfw/CodePoint.cs index 142dbc7..09a60c9 100644 --- a/vke/src/glfw/CodePoint.cs +++ b/vke/src/glfw/CodePoint.cs @@ -1,43 +1,39 @@ -using System.Text; +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System.Runtime.InteropServices; +using System.Text; namespace Glfw { - /// - /// Represents a native UTF32 codepoint. - /// - public struct CodePoint + /// + /// Represents a native UTF32 codepoint. + /// + [StructLayout (LayoutKind.Explicit)] + public struct CodePoint { - /// - /// The numeric value of the codepoint. - /// - public readonly uint Value; - - /// - /// Casts the codepoint to System.Char. - /// - /// - /// The character representation of the codepoint. - /// - public unsafe char ToChar() - { - uint value = this.Value; - - char result; - - Encoding.UTF32.GetChars((byte*)&value, 4, &result, 1); - - return result; - } - + /// + /// The numeric value of the codepoint. + /// + [FieldOffset (0)] public readonly uint Value; + [FieldOffset (0)] readonly byte byte0; + [FieldOffset (1)] readonly byte byte1; + [FieldOffset (2)] readonly byte byte2; + [FieldOffset (3)] readonly byte byte3; + /// + /// Casts the codepoint to System.Char. + /// + /// + /// The character representation of the codepoint. + /// + public char ToChar() => Encoding.UTF32.GetChars (new byte[] { byte0, byte0, byte0, byte0 })[0]; /// /// Converts the value of this instance to its equivalent string representation. /// /// /// A string containing the character representation of the codepoint. /// - public override string ToString() - { - return this.ToChar().ToString(); - } + public override string ToString() => ToChar().ToString(); } } diff --git a/vke/src/glfw/Delegates.cs b/vke/src/glfw/Delegates.cs index 2f2acb6..bfcbb0e 100644 --- a/vke/src/glfw/Delegates.cs +++ b/vke/src/glfw/Delegates.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)using System; +using System; using System.Runtime.InteropServices; namespace Glfw { diff --git a/vke/src/glfw/ErrorCode.cs b/vke/src/glfw/ErrorCode.cs index c757488..ef76890 100644 --- a/vke/src/glfw/ErrorCode.cs +++ b/vke/src/glfw/ErrorCode.cs @@ -1,4 +1,8 @@ -namespace Glfw +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +namespace Glfw { /// /// Indicates the general category of an error. diff --git a/vke/src/glfw/Glfw3.cs b/vke/src/glfw/Glfw3.cs index 27e7497..1531d79 100644 --- a/vke/src/glfw/Glfw3.cs +++ b/vke/src/glfw/Glfw3.cs @@ -1,9 +1,11 @@ -using System; -using System.Text; +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; using System.Runtime.InteropServices; -namespace Glfw -{ +namespace Glfw { public enum CursorShape { Arrow = 0x00036001, @@ -16,7 +18,7 @@ namespace Glfw /// /// Interop functions for the GLFW3 API. /// - public unsafe static class Glfw3 + public static class Glfw3 { /// /// The base name for the GLFW3 library. @@ -185,7 +187,7 @@ namespace Glfw /// An array of extension names, or Null if an error occurred. /// [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetRequiredInstanceExtensions")] - public static extern byte** GetRequiredInstanceExtensions(out int count); + public static extern IntPtr GetRequiredInstanceExtensions(out int count); /// /// Sets the size callback of the specified window, which is called @@ -229,7 +231,7 @@ namespace Glfw /// if an error occurred. /// [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetMonitors")] - public static extern MonitorHandle* GetMonitors(out int count); + public static extern IntPtr GetMonitors(out int count); /// /// Returns the primary monitor. This is usually the monitor where @@ -320,7 +322,7 @@ namespace Glfw /// An array of video modes, or Null if an error occurred. /// [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetVideoModes")] - public static extern VideoMode* GetVideoModes(MonitorHandle monitor, out int count); + public static extern IntPtr GetVideoModes(MonitorHandle monitor, out int count); /// /// Returns the current video mode of the specified monitor. If you @@ -448,13 +450,14 @@ namespace Glfw /// public static string[] GetRequiredInstanceExtensions() { - byte** namePointer = GetRequiredInstanceExtensions(out int count); + IntPtr names = GetRequiredInstanceExtensions(out int count); var result = new string[count]; for (int nameIndex = 0; nameIndex < count; nameIndex++) { - result[nameIndex] = Marshal.PtrToStringAnsi(new System.IntPtr (namePointer[nameIndex])); + IntPtr name = Marshal.ReadIntPtr (names, nameIndex); + result[nameIndex] = Marshal.PtrToStringAnsi(name); } return result; @@ -471,14 +474,12 @@ namespace Glfw /// public static MonitorHandle[] GetMonitors() { - MonitorHandle* monitorPointer = GetMonitors(out int count); + IntPtr monitors = GetMonitors(out int count); var result = new MonitorHandle[count]; - for (int i = 0; i < count; i++) - { - result[i] = monitorPointer[i]; - } + for (int i = 0; i < count; i++) + result[i] = new MonitorHandle(Marshal.ReadIntPtr(monitors, i)); return result; } @@ -497,14 +498,12 @@ namespace Glfw /// public static VideoMode[] GetVideoModes(MonitorHandle monitor) { - VideoMode* videoModePointer = GetVideoModes(monitor, out int count); + IntPtr videoModes = GetVideoModes(monitor, out int count); var result = new VideoMode[count]; - for (int i = 0; i < count; i++) - { - result[i] = videoModePointer[i]; - } + for (int i = 0; i < count; i++) + result[i] = Marshal.PtrToStructure(Marshal.ReadIntPtr(videoModes, i)); return result; } diff --git a/vke/src/glfw/InputAction.cs b/vke/src/glfw/InputAction.cs index a0f7ee3..3ee57f7 100644 --- a/vke/src/glfw/InputAction.cs +++ b/vke/src/glfw/InputAction.cs @@ -1,4 +1,8 @@ -namespace Glfw +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +namespace Glfw { /// /// Represents the action of an input key event or the state of a key. diff --git a/vke/src/glfw/Key.cs b/vke/src/glfw/Key.cs index 0cc2a64..1e8c19d 100644 --- a/vke/src/glfw/Key.cs +++ b/vke/src/glfw/Key.cs @@ -1,4 +1,8 @@ -namespace Glfw +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +namespace Glfw { /// /// Represents a key on a keyboard. diff --git a/vke/src/glfw/Modifier.cs b/vke/src/glfw/Modifier.cs index 55da485..98205c7 100644 --- a/vke/src/glfw/Modifier.cs +++ b/vke/src/glfw/Modifier.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; namespace Glfw { diff --git a/vke/src/glfw/MonitorEvent.cs b/vke/src/glfw/MonitorEvent.cs index 340ba6e..d93397b 100644 --- a/vke/src/glfw/MonitorEvent.cs +++ b/vke/src/glfw/MonitorEvent.cs @@ -1,4 +1,8 @@ -namespace Glfw +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +namespace Glfw { /// /// Events that may be raised from a monitor callback. diff --git a/vke/src/glfw/MonitorHandle.cs b/vke/src/glfw/MonitorHandle.cs index 16b8a71..38ed035 100644 --- a/vke/src/glfw/MonitorHandle.cs +++ b/vke/src/glfw/MonitorHandle.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; namespace Glfw { @@ -7,28 +11,20 @@ namespace Glfw /// public struct MonitorHandle { - internal MonitorHandle(System.IntPtr handle) - { - this.handle = handle; - } - - private System.IntPtr handle; + readonly IntPtr handle; - /// - /// Gets the underlying native pointer to the monitor object. - /// - public IntPtr RawHandle + internal MonitorHandle(IntPtr handle) { - get - { - return this.handle; - } + this.handle = handle; } - + /// + /// Gets the underlying native pointer to the monitor object. + /// + public IntPtr RawHandle => handle; /// /// A read-only field that represents a MonitorHandle that has been /// inititalised to zero. /// - public static readonly MonitorHandle Zero = new MonitorHandle (System.IntPtr.Zero); + public static readonly MonitorHandle Zero = new MonitorHandle (IntPtr.Zero); } } diff --git a/vke/src/glfw/MouseButton.cs b/vke/src/glfw/MouseButton.cs index 12425ad..b29184a 100644 --- a/vke/src/glfw/MouseButton.cs +++ b/vke/src/glfw/MouseButton.cs @@ -1,4 +1,8 @@ -namespace Glfw +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +namespace Glfw { /// /// The index and name of mouse buttons for callbacks. diff --git a/vke/src/glfw/NativeString.cs b/vke/src/glfw/NativeString.cs index f191e33..02181cb 100644 --- a/vke/src/glfw/NativeString.cs +++ b/vke/src/glfw/NativeString.cs @@ -1,6 +1,10 @@ using System; using System.Runtime.InteropServices; +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) namespace Glfw { /// @@ -8,43 +12,31 @@ namespace Glfw /// public struct NativeString { - internal NativeString(System.IntPtr pointer) + internal NativeString(IntPtr pointer) { this.pointer = pointer; } - private System.IntPtr pointer; - - /// - /// Gets the marshalled string value for this native string. - /// - public string Value - { - get - { - if (this.IsNull) - { - throw new NullReferenceException(); - } - - return Marshal.PtrToStringAnsi(this.pointer); - } - } + readonly IntPtr pointer; + /// + /// Gets the marshalled string value for this native string. + /// + public string Value => IsNull ? throw new NullReferenceException () : Marshal.PtrToStringAnsi (this.pointer); /// /// Gets a value indicating whether the pointer wrapped by this /// instance is null. /// - public bool IsNull => this.pointer == System.IntPtr.Zero; + public bool IsNull => pointer == IntPtr.Zero; /// /// The underlying pointer wrapped by this instance. /// - public IntPtr RawPointer => this.pointer; + public IntPtr RawPointer => pointer; public override string ToString() { - return this.Value; + return Value; } } } diff --git a/vke/src/glfw/VideoMode.cs b/vke/src/glfw/VideoMode.cs index 8a60269..baeb196 100644 --- a/vke/src/glfw/VideoMode.cs +++ b/vke/src/glfw/VideoMode.cs @@ -8,15 +8,11 @@ namespace Glfw [StructLayout(LayoutKind.Sequential)] public struct VideoMode { - private int width; - - private int height; - - private int redBits; - - private int greenBits; - - private int blueBits; + private readonly int width; + private readonly int height; + private readonly int redBits; + private readonly int greenBits; + private readonly int blueBits; /// /// The resolution, in screen coordinates, of the video mode. diff --git a/vke/src/glfw/VideoModePointer.cs b/vke/src/glfw/VideoModePointer.cs index e740772..66631c6 100644 --- a/vke/src/glfw/VideoModePointer.cs +++ b/vke/src/glfw/VideoModePointer.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; using System.Runtime.InteropServices; namespace Glfw @@ -8,27 +12,23 @@ namespace Glfw /// public struct VideoModePointer { - internal VideoModePointer(System.IntPtr pointer) + private readonly IntPtr pointer; + internal VideoModePointer (IntPtr pointer) { this.pointer = pointer; } - - private System.IntPtr pointer; - /// /// Gets the VideoMode value at the referenced memory location. /// - public VideoMode Value => this.IsNull ? throw new NullReferenceException() : Marshal.PtrToStructure(this.pointer); - + public VideoMode Value => IsNull ? throw new NullReferenceException() : Marshal.PtrToStructure(pointer); /// /// Gets a value indicating whether the pointer wrapped by this /// instance is null. /// - public bool IsNull => this.pointer == System.IntPtr.Zero; - + public bool IsNull => pointer == IntPtr.Zero; /// /// The underlying pointer wrapped by this instance. /// - public IntPtr RawPointer => this.pointer; + public IntPtr RawPointer => pointer; } } diff --git a/vke/src/glfw/WindowAttribute.cs b/vke/src/glfw/WindowAttribute.cs index 5d862af..f772667 100644 --- a/vke/src/glfw/WindowAttribute.cs +++ b/vke/src/glfw/WindowAttribute.cs @@ -1,4 +1,8 @@ -namespace Glfw +// Copyright (c) 2019 Andrew Armstrong/FacticiusVir +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +namespace Glfw { /// /// Attributes of a window or its framebuffer or context, that can be diff --git a/vke/src/ktx.cs b/vke/src/ktx.cs index cc68854..4ea7c41 100644 --- a/vke/src/ktx.cs +++ b/vke/src/ktx.cs @@ -1,28 +1,6 @@ -// -// ktx.cs +// Copyright (c) 2019 Jean-Philippe Bruyère // -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; using System.IO;