pixel rendering functional
This commit is contained in:
commit
e29c576356
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
build
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "dlib"]
|
||||
path = dlib
|
||||
url = https://git.sleepy.day/sleepy-day/dlib.git
|
||||
143
build.d
Executable file
143
build.d
Executable file
@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env rdmd
|
||||
|
||||
import std.stdio;
|
||||
import std.file;
|
||||
import std.array;
|
||||
import std.process;
|
||||
import core.stdc.stdlib : exit;
|
||||
|
||||
enum Mode
|
||||
{
|
||||
Debug,
|
||||
Release,
|
||||
};
|
||||
|
||||
enum Compiler
|
||||
{
|
||||
LDC,
|
||||
DMD,
|
||||
};
|
||||
|
||||
// Config
|
||||
Mode mode;
|
||||
Compiler compiler;
|
||||
|
||||
int COMPILER = 0;
|
||||
int VERSION = 1;
|
||||
int CFLAG = 2;
|
||||
int OUT = 3;
|
||||
|
||||
// General globals
|
||||
string[] ARGS;
|
||||
|
||||
bool HasFlag(string flag)
|
||||
{
|
||||
bool result;
|
||||
|
||||
foreach(arg; ARGS)
|
||||
{
|
||||
if(arg == flag)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
ARGS = args;
|
||||
|
||||
string out_name = "build/Pixel";
|
||||
|
||||
if(HasFlag("release")) mode = Mode.Release;
|
||||
if(HasFlag("dmd")) compiler = Compiler.DMD;
|
||||
|
||||
enum string[string] DMD_LOOKUP = [
|
||||
"compiler": "dmd",
|
||||
"version": "-version=",
|
||||
"cflag": "-P=",
|
||||
"out": "-of=",
|
||||
"include": "-I=",
|
||||
];
|
||||
|
||||
enum string[string] LDC_LOOKUP = [
|
||||
"compiler": "ldc2",
|
||||
"version": "--d-version=",
|
||||
"cflag": "--Xcc=",
|
||||
"out": "--of=",
|
||||
"include": "-I",
|
||||
];
|
||||
|
||||
auto lookup = compiler == Compiler.DMD ? DMD_LOOKUP : LDC_LOOKUP;
|
||||
|
||||
string[] libs = ["SDL3", "vulkan", "X11", "Xfixes", "stdc++"];
|
||||
string[] dirs = ["dlib/dlib", "dlib/vulkan", "source"];
|
||||
string[] files = ["dlib/build/libvma.a"];
|
||||
string[] cflags = [
|
||||
"-DBUILD_VULKAN",
|
||||
"-Idlib/external",
|
||||
];
|
||||
string[] versions = ["BUILD_VULKAN"];
|
||||
string[] scripts = [
|
||||
"./dlib/build.sh",
|
||||
"glslang --target-env vulkan1.2 -gVS -o build/pixel.comp.spv shaders/pixel.comp.glsl"
|
||||
];
|
||||
string[] flags = [
|
||||
"-Jbuild",
|
||||
"-Jdlib/build",
|
||||
lookup["out"] ~ out_name,
|
||||
lookup["include"] ~ "dlib/dlib",
|
||||
];
|
||||
|
||||
if(HasFlag("-v")) flags ~= "-v";
|
||||
|
||||
final switch(mode)
|
||||
{
|
||||
case Mode.Debug:
|
||||
{
|
||||
versions ~= "VULKAN_DEBUG";
|
||||
} break;
|
||||
case Mode.Release:
|
||||
{
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
execute(["mkdir", "-p"]);
|
||||
|
||||
foreach(path; dirs)
|
||||
{
|
||||
foreach(string file_name; dirEntries(path, "*.{d,c}", SpanMode.depth))
|
||||
{
|
||||
files ~= file_name;
|
||||
}
|
||||
}
|
||||
|
||||
foreach(lib; libs)
|
||||
{
|
||||
flags ~= "-L-l" ~ lib;
|
||||
}
|
||||
|
||||
foreach(cflag; cflags)
|
||||
{
|
||||
flags ~= lookup["cflag"] ~ cflag;
|
||||
}
|
||||
|
||||
foreach(ver; versions)
|
||||
{
|
||||
flags ~= lookup["version"] ~ ver;
|
||||
}
|
||||
|
||||
foreach(script; scripts)
|
||||
{
|
||||
execute(script.split(" "));
|
||||
}
|
||||
|
||||
auto result = execute([lookup["compiler"]] ~ files ~ flags);
|
||||
|
||||
writeln(result.output);
|
||||
exit(result.status);
|
||||
}
|
||||
1
dlib
Submodule
1
dlib
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c65b5401aba77d11562b544964d8db62cb65bb72
|
||||
38
shaders/pixel.comp.glsl
Normal file
38
shaders/pixel.comp.glsl
Normal file
@ -0,0 +1,38 @@
|
||||
#version 460
|
||||
|
||||
#define u32 uint
|
||||
#define f32 float
|
||||
|
||||
layout(local_size_x = 32, local_size_y = 32) in;
|
||||
|
||||
layout(set = 1, binding = 0, rgba32f) uniform image2D DrawImage;
|
||||
|
||||
layout(set = 1, binding = 1) buffer display_buffer
|
||||
{
|
||||
u32 pixels[];
|
||||
};
|
||||
|
||||
layout(push_constant) uniform PushConst
|
||||
{
|
||||
uvec2 src_resolution;
|
||||
} PC;
|
||||
|
||||
void main()
|
||||
{
|
||||
uvec2 src_resolution = PC.src_resolution;
|
||||
uvec2 dst_resolution = uvec2(imageSize(DrawImage).xy);
|
||||
|
||||
uvec2 scale = dst_resolution/src_resolution;
|
||||
uvec2 pos = uvec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
if(pos.x < dst_resolution.x && pos.y < dst_resolution.y)
|
||||
{
|
||||
uvec2 scaled_pos = pos/scale;
|
||||
|
||||
u32 index = scaled_pos.y*src_resolution.x + scaled_pos.x;
|
||||
|
||||
vec4 color = bool(pixels[index]) ? vec4(1.0) : vec4(0.0);
|
||||
imageStore(DrawImage, ivec2(pos.xy), color);
|
||||
}
|
||||
}
|
||||
|
||||
216
source/app.d
Normal file
216
source/app.d
Normal file
@ -0,0 +1,216 @@
|
||||
import std.stdio;
|
||||
|
||||
import dlib.aliases;
|
||||
import dlib.util;
|
||||
|
||||
import dlibincludes;
|
||||
import vulkan;
|
||||
|
||||
enum SDLWindowFlags : u64
|
||||
{
|
||||
FULLSCREEN = 0x0000000000000001, /**< window is in fullscreen mode */
|
||||
OPENGL = 0x0000000000000002, /**< window usable with OpenGL context */
|
||||
OCCLUDED = 0x0000000000000004, /**< window is occluded */
|
||||
HIDDEN = 0x0000000000000008, /**< window is neither mapped onto the desktop nor shown in the taskbar/dock/window list; SDL_ShowWindow() is required for it to become visible */
|
||||
BORDERLESS = 0x0000000000000010, /**< no window decoration */
|
||||
RESIZABLE = 0x0000000000000020, /**< window can be resized */
|
||||
MINIMIZED = 0x0000000000000040, /**< window is minimized */
|
||||
MAXIMIZED = 0x0000000000000080, /**< window is maximized */
|
||||
MOUSE_GRABBED = 0x0000000000000100, /**< window has grabbed mouse input */
|
||||
INPUT_FOCUS = 0x0000000000000200, /**< window has input focus */
|
||||
MOUSE_FOCUS = 0x0000000000000400, /**< window has mouse focus */
|
||||
EXTERNAL = 0x0000000000000800, /**< window not created by SDL */
|
||||
MODAL = 0x0000000000001000, /**< window is modal */
|
||||
HIGH_PIXEL_DENSITY = 0x0000000000002000, /**< window uses high pixel density back buffer if possible */
|
||||
MOUSE_CAPTURE = 0x0000000000004000, /**< window has mouse captured (unrelated to MOUSE_GRABBED) */
|
||||
MOUSE_RELATIVE_MODE = 0x0000000000008000, /**< window has relative mode enabled */
|
||||
ALWAYS_ON_TOP = 0x0000000000010000, /**< window should always be above others */
|
||||
UTILITY = 0x0000000000020000, /**< window should be treated as a utility window, not showing in the task bar and window list */
|
||||
TOOLTIP = 0x0000000000040000, /**< window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window */
|
||||
POPUP_MENU = 0x0000000000080000, /**< window should be treated as a popup menu, requires a parent window */
|
||||
KEYBOARD_GRABBED = 0x0000000000100000, /**< window has grabbed keyboard input */
|
||||
FILL_DOCUMENT = 0x0000000000200000, /**< window is in fill-document mode (Emscripten only), since SDL 3.4.0 */
|
||||
VULKAN = 0x0000000010000000, /**< window usable for Vulkan surface */
|
||||
METAL = 0x0000000020000000, /**< window usable for Metal view */
|
||||
TRANSPARENT = 0x0000000040000000, /**< window with transparent buffer */
|
||||
NOT_FOCUSABLE = 0x0000000080000000, /**< window should not be focusable */
|
||||
}
|
||||
|
||||
alias SDL_WINDOW = SDLWindowFlags;
|
||||
|
||||
struct PxDisplay
|
||||
{
|
||||
MappedBuffer!(u32) mapped_buffer;
|
||||
u32[] buffer;
|
||||
UVec2 resolution;
|
||||
Descriptor descriptor;
|
||||
}
|
||||
|
||||
const u32 RESOLUTION_X = 640;
|
||||
const u32 RESOLUTION_Y = 360;
|
||||
const u32 BUFFER_SIZE = RESOLUTION_X * RESOLUTION_Y;
|
||||
const UVec2 RESOLUTION = UVec2(RESOLUTION_X, RESOLUTION_Y);
|
||||
|
||||
struct PxWork
|
||||
{
|
||||
SDL_Window* window;
|
||||
PxDisplay[FRAME_OVERLAP] displays;
|
||||
Descriptor[FRAME_OVERLAP] draw_images;
|
||||
PushConst pc;
|
||||
DescSetLayout desc_set_layout;
|
||||
DescSet[FRAME_OVERLAP] desc_sets;
|
||||
PipelineLayout pipeline_layout;
|
||||
Pipeline pipeline;
|
||||
UVec2 dst_resolution;
|
||||
bool[FRAME_OVERLAP] reload_image;
|
||||
}
|
||||
|
||||
struct PushConst
|
||||
{
|
||||
UVec2 src_resolution;
|
||||
}
|
||||
|
||||
PxWork px;
|
||||
const u8[] SHADER_SRC = import("pixel.comp.spv");
|
||||
|
||||
void
|
||||
CreateDrawImage(Descriptor* desc, UVec2 resolution)
|
||||
{
|
||||
CreateDescriptor(
|
||||
desc,
|
||||
DescInfo(
|
||||
type: DT.StorageImage,
|
||||
format: FMT.RGBA_F32,
|
||||
usage: IU.Convert,
|
||||
w: resolution.x,
|
||||
h: resolution.y,
|
||||
ch: 4,
|
||||
binding: 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if(!SDL_Init(SDL_INIT_VIDEO))
|
||||
{
|
||||
Errf("Failed to init SDL [%s]", SDL_GetError());
|
||||
assert(false);
|
||||
}
|
||||
|
||||
px.window = SDL_CreateWindow("Video Game", 1920, 1080, SDL_WINDOW.VULKAN);
|
||||
if(!px.window)
|
||||
{
|
||||
Errf("Failed to create SDL window [%s]", SDL_GetError());
|
||||
assert(false);
|
||||
}
|
||||
|
||||
VulkanBuildInfo build_info = {
|
||||
application_name: "Video Game",
|
||||
engine_name: "PxWork",
|
||||
platform_handles: {
|
||||
sdl: true,
|
||||
sdl_window: px.window,
|
||||
},
|
||||
};
|
||||
|
||||
Init(build_info, MB(16), MB(8));
|
||||
|
||||
DescLayoutBinding[2] layout_bindings = [
|
||||
{ binding: 0, descriptorType: DT.StorageImage, descriptorCount: 1, stageFlags: SS.All },
|
||||
{ binding: 1, descriptorType: DT.Storage, descriptorCount: 1, stageFlags: SS.All },
|
||||
];
|
||||
|
||||
px.desc_set_layout = CreateDescSetLayout(layout_bindings);
|
||||
px.pipeline_layout = CreatePipelineLayout(px.desc_set_layout, PushConst.sizeof, true);
|
||||
|
||||
px.dst_resolution = UVec2(GetExtent());
|
||||
px.pc.src_resolution = RESOLUTION;
|
||||
|
||||
foreach(i; 0 .. FRAME_OVERLAP)
|
||||
{
|
||||
px.displays[i].mapped_buffer = CreateMappedBuffer!(u32)(BT.Storage, BUFFER_SIZE);
|
||||
px.displays[i].buffer = px.displays[i].mapped_buffer.data;
|
||||
px.displays[i].resolution = RESOLUTION;
|
||||
|
||||
px.displays[i].descriptor.buffer = px.displays[i].mapped_buffer.base;
|
||||
px.displays[i].descriptor.type = DT.Storage;
|
||||
px.displays[i].descriptor.binding = 1;
|
||||
|
||||
CreateDrawImage(&px.draw_images[i], px.dst_resolution);
|
||||
|
||||
px.desc_sets[i] = AllocDescSet(px.desc_set_layout);
|
||||
|
||||
Write(px.desc_sets[i], &px.draw_images[i]);
|
||||
Write(px.desc_sets[i], &px.displays[i].descriptor);
|
||||
}
|
||||
|
||||
CompPipelineInfo pipeline_info = {
|
||||
shader: cast(u8[])SHADER_SRC,
|
||||
layout: px.pipeline_layout,
|
||||
};
|
||||
|
||||
px.pipeline = CreateComputePipeline(&pipeline_info);
|
||||
|
||||
SetClearColors([0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 0.0, 0.0]);
|
||||
|
||||
foreach(i; 0 .. FRAME_OVERLAP)
|
||||
{
|
||||
foreach(j; 0 .. RESOLUTION.y)
|
||||
{
|
||||
u32 cmp = j%2 == 0 ? 0 : 1;
|
||||
foreach(k; 0 .. RESOLUTION.x)
|
||||
{
|
||||
px.displays[i].buffer[j*RESOLUTION.x + k] = k%2 == cmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 index = 0;
|
||||
SDL_Event event;
|
||||
bool run = true;
|
||||
while(run)
|
||||
{
|
||||
while(SDL_PollEvent(&event))
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_EVENT_QUIT:
|
||||
{
|
||||
run = false;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
BeginFrame();
|
||||
|
||||
UVec2 extent = UVec2(GetExtent());
|
||||
if(extent.v != px.dst_resolution.v)
|
||||
{
|
||||
px.dst_resolution = extent;
|
||||
foreach(i; 0 .. FRAME_OVERLAP)
|
||||
{
|
||||
px.reload_image[index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(px.reload_image[index])
|
||||
{
|
||||
Destroy(&px.draw_images[index]);
|
||||
CreateDrawImage(&px.draw_images[index], px.dst_resolution);
|
||||
Write(px.desc_sets[index], &px.draw_images[index]);
|
||||
|
||||
px.reload_image[index] = false;
|
||||
}
|
||||
|
||||
PrepComputeImage(&px.draw_images[index]);
|
||||
Bind(px.pipeline, px.desc_sets[index]);
|
||||
PushConstants(px.pipeline, &px.pc);
|
||||
Dispatch();
|
||||
|
||||
SubmitAndPresent(&px.draw_images[index]);
|
||||
|
||||
index = (index+1)%FRAME_OVERLAP;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user