hitting this damn shader module again. Very unergonomic interface with the fact that the entry point doesn't just own the shadermodule
This commit is contained in:
@@ -1,17 +1,23 @@
|
||||
use vulkano::device::{Device, Queue};
|
||||
use vulkano::instance::{PhysicalDevice, QueueFamily};
|
||||
use vulkano::instance::{PhysicalDevice, QueueFamily, LayerProperties};
|
||||
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract, GraphicsPipelineBuilder};
|
||||
use std::sync::Arc;
|
||||
use std::ffi::CStr;
|
||||
use std::path::PathBuf;
|
||||
use shade_runner as sr;
|
||||
use vulkano::framebuffer::{Subpass, RenderPassAbstract, Framebuffer, FramebufferAbstract};
|
||||
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule, SpecializationConstants, SpecializationMapEntry};
|
||||
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule, SpecializationConstants, SpecializationMapEntry, GeometryShaderExecutionMode, GraphicsEntryPointAbstract, GraphicsEntryPoint, EmptyEntryPointDummy};
|
||||
use vulkano::swapchain::Capabilities;
|
||||
use vulkano::pipeline::vertex::SingleBufferDefinition;
|
||||
use crate::util::vertex_3d::Vertex3D;
|
||||
use vulkano::pipeline::depth_stencil::{DepthStencil, Stencil, StencilOp, Compare, DepthBounds};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use shade_runner::{Layout, Output, Input};
|
||||
use vulkano::descriptor::pipeline_layout::PipelineLayout;
|
||||
use std::marker::PhantomData;
|
||||
use vulkano::pipeline::input_assembly::PrimitiveTopology;
|
||||
use vulkano::pipeline::blend::{Blend, AttachmentsBlend};
|
||||
use vulkano::pipeline::vertex::BufferlessDefinition;
|
||||
|
||||
/// Inheriting this gives private functions to grab resources
|
||||
trait CompiledGraphicsPipelineResources {
|
||||
@@ -42,9 +48,14 @@ trait CompiledGraphicsPipelineResources {
|
||||
shader_path.push(PathBuf::from(filename.clone() + ".geom"));
|
||||
paths.push((shader_type, shader_path));
|
||||
}
|
||||
ShaderType::TESSELLATION => {
|
||||
ShaderType::TESSELLATION_CONTROL => {
|
||||
let mut shader_path = shader_path.clone();
|
||||
shader_path.push(PathBuf::from(filename.clone() + ".tess"));
|
||||
shader_path.push(PathBuf::from(filename.clone() + ".tesscont"));
|
||||
paths.push((shader_type, shader_path));
|
||||
}
|
||||
ShaderType::TESSELLATION_EVALUATION => {
|
||||
let mut shader_path = shader_path.clone();
|
||||
shader_path.push(PathBuf::from(filename.clone() + ".tesseval"));
|
||||
paths.push((shader_type, shader_path));
|
||||
}
|
||||
}
|
||||
@@ -65,7 +76,7 @@ pub trait CompiledGraphicsPipeline {
|
||||
fn get_handle(&self) -> Arc<CompiledGraphicsPipelineHandle>;
|
||||
fn get_pipeline(&self) -> Arc<dyn GraphicsPipelineAbstract + Sync + Send>;
|
||||
fn recompile(self, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>)
|
||||
-> Self where Self: Sized;
|
||||
-> Self where Self: Sized;
|
||||
}
|
||||
|
||||
/// Legacy ShaderType enum for single type shaders.
|
||||
@@ -116,84 +127,136 @@ impl CompiledGraphicsPipeline for GenericShader {
|
||||
|
||||
fn recompile(self, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>) -> GenericShader {
|
||||
GenericShader::new(self.name,
|
||||
self.shader_types,
|
||||
self.device,
|
||||
self.handle,
|
||||
render_pass.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Realistically, what should the API for this thing look like...
|
||||
|
||||
It's going to just generate a pipeline. But that consists of loading and compiling various shaders,
|
||||
and generating a pipeline for those shaders and other customer behaviour.
|
||||
|
||||
This best works I think if I allow users to
|
||||
A.) impl from a base trait which allows resource lookup
|
||||
B.) Generate 1 of each of the types of shaders
|
||||
C.) Modify specilization constants, whatever that might mean
|
||||
D.) impl from a base trait which defines it's interface
|
||||
|
||||
*/
|
||||
|
||||
|
||||
impl GenericShader {
|
||||
|
||||
pub fn ret(&self) -> Option<GraphicsEntryPoint<
|
||||
ShaderSpecializationConstants,
|
||||
Input,
|
||||
Output,
|
||||
Layout>> {
|
||||
|
||||
let compiled_shader = sr::load_vertex("dfqwefqwef")
|
||||
.expect("Shader didn't compile");
|
||||
|
||||
let vulkano_entry =
|
||||
sr::parse(&compiled_shader)
|
||||
.expect("failed to parse");
|
||||
|
||||
let shader_module: Arc<ShaderModule> = unsafe {
|
||||
ShaderModule::from_words(self.device.clone(), &compiled_shader.spriv.clone())
|
||||
}.unwrap();
|
||||
|
||||
let s = ShaderType::VERTEX;
|
||||
|
||||
let shader_type = match s {
|
||||
ShaderType::VERTEX => { GraphicsShaderType::Vertex }
|
||||
ShaderType::FRAGMENT => { GraphicsShaderType::Fragment }
|
||||
ShaderType::GEOMETRY => { GraphicsShaderType::Geometry(GeometryShaderExecutionMode::Triangles) }
|
||||
ShaderType::TESSELLATION_CONTROL => { GraphicsShaderType::TessellationControl }
|
||||
ShaderType::TESSELLATION_EVALUATION => { GraphicsShaderType::TessellationEvaluation }
|
||||
};
|
||||
|
||||
unsafe {
|
||||
Some(GraphicsEntryPoint {
|
||||
module: &shader_module,
|
||||
name: &CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||
input: vulkano_entry.input.unwrap(),
|
||||
layout: vulkano_entry.layout,
|
||||
output: vulkano_entry.output.unwrap(),
|
||||
ty: shader_type,
|
||||
marker: PhantomData::default(),
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
/// This will explode when the shader does not want to compile
|
||||
pub fn new(filename: String,
|
||||
shader_types: HashSet<ShaderType>,
|
||||
device: Arc<Device>,
|
||||
handle: Arc<CompiledGraphicsPipelineHandle>,
|
||||
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>) -> GenericShader {
|
||||
|
||||
let mut shader_types : HashSet<ShaderType> = vec![
|
||||
ShaderType::VERTEX,
|
||||
ShaderType::FRAGMENT,
|
||||
].iter().cloned().collect();
|
||||
|
||||
let filenames = GenericShader::get_paths(filename.clone(), shader_types.clone());
|
||||
|
||||
// TODO: better compile message, run til successful compile
|
||||
|
||||
|
||||
// let mut c = Vec::new();
|
||||
|
||||
let mut vertex_entry_point : Option<GraphicsEntryPoint<ShaderSpecializationConstants,Input,Output,Layout>>
|
||||
= None;
|
||||
let mut fragment_entry_point : Option<GraphicsEntryPoint<ShaderSpecializationConstants,Input,Output,Layout>>
|
||||
= None;
|
||||
|
||||
for shader in filenames {
|
||||
match shader.0 {
|
||||
ShaderType::VERTEX => {
|
||||
let shader = sr::load(filenames.0, filenames.1)
|
||||
.expect("Shader didn't compile");
|
||||
let compiled_shader = sr::load_vertex(shader.1)
|
||||
.expect("Shader didn't compile");
|
||||
|
||||
let vulkano_entry =
|
||||
sr::parse(&shader)
|
||||
.expect("failed to parse");
|
||||
}
|
||||
ShaderType::FRAGMENT => {
|
||||
let vulkano_entry =
|
||||
sr::parse(&compiled_shader)
|
||||
.expect("failed to parse");
|
||||
|
||||
}
|
||||
ShaderType::GEOMETRY => {
|
||||
let shader_module: Arc<ShaderModule> = unsafe {
|
||||
ShaderModule::from_words(device.clone(), &compiled_shader.spriv.clone())
|
||||
}.unwrap();
|
||||
|
||||
}
|
||||
ShaderType::TESSELLATION => {
|
||||
let shader_type = match shader.0 {
|
||||
ShaderType::VERTEX => { GraphicsShaderType::Vertex }
|
||||
ShaderType::FRAGMENT => { GraphicsShaderType::Fragment }
|
||||
ShaderType::GEOMETRY => { GraphicsShaderType::Geometry(GeometryShaderExecutionMode::Triangles) }
|
||||
ShaderType::TESSELLATION_CONTROL => { GraphicsShaderType::TessellationControl }
|
||||
ShaderType::TESSELLATION_EVALUATION => { GraphicsShaderType::TessellationEvaluation }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
let entry_point: Option<GraphicsEntryPoint<
|
||||
ShaderSpecializationConstants,
|
||||
Input,
|
||||
Output,
|
||||
Layout>> = unsafe {
|
||||
Some(GraphicsEntryPoint {
|
||||
module: &shader_module,
|
||||
name: &CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||
input: vulkano_entry.input.unwrap(),
|
||||
layout: vulkano_entry.layout,
|
||||
output: vulkano_entry.output.unwrap(),
|
||||
ty: shader_type,
|
||||
marker: PhantomData::default(),
|
||||
})
|
||||
};
|
||||
|
||||
let shader_type = match shader.0 {
|
||||
ShaderType::VERTEX => { vertex_entry_point = Some(entry_point.clone().unwrap()) }
|
||||
ShaderType::FRAGMENT => { fragment_entry_point = Some(entry_point.clone().unwrap()) }
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// c.push((entry_point.unwrap().clone(), shader_module.clone()));
|
||||
}
|
||||
|
||||
let fragment_shader_module: Arc<ShaderModule> = unsafe {
|
||||
let filenames1 = GenericShader::get_path(filename.clone());
|
||||
let shader1 = sr::load(filenames1.0, filenames1.1)
|
||||
.expect("Shader didn't compile");
|
||||
ShaderModule::from_words(device.clone(), &shader1.fragment.clone())
|
||||
}.unwrap();
|
||||
|
||||
|
||||
let vertex_shader_module: Arc<ShaderModule> = unsafe {
|
||||
|
||||
let filenames1 = GenericShader::get_path(filename.clone());
|
||||
let shader1 = sr::load(filenames1.0, filenames1.1)
|
||||
.expect("Shader didn't compile");
|
||||
ShaderModule::from_words(device.clone(), &shader1.vertex.clone())
|
||||
}.unwrap();
|
||||
|
||||
|
||||
let frag_entry_point = unsafe {
|
||||
Some(fragment_shader_module.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||
vulkano_entry.frag_input,
|
||||
vulkano_entry.frag_output,
|
||||
vulkano_entry.frag_layout,
|
||||
GraphicsShaderType::Fragment))
|
||||
};
|
||||
|
||||
let vertex_entry_point = unsafe {
|
||||
Some(vertex_shader_module.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||
vulkano_entry.vert_input,
|
||||
vulkano_entry.vert_output,
|
||||
vulkano_entry.vert_layout,
|
||||
GraphicsShaderType::Vertex))
|
||||
};
|
||||
|
||||
let stencil = DepthStencil {
|
||||
depth_compare: Compare::Less,
|
||||
depth_write: true,
|
||||
@@ -218,13 +281,13 @@ impl GenericShader {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
GenericShader {
|
||||
graphics_pipeline: Some(Arc::new(GraphicsPipeline::start()
|
||||
graphics_pipeline:
|
||||
Some(Arc::new(GraphicsPipeline::start()
|
||||
|
||||
.vertex_input(SingleBufferDefinition::<Vertex3D>::new())
|
||||
|
||||
.vertex_shader(vertex_entry_point.clone().unwrap(), ShaderSpecializationConstants {
|
||||
.vertex_shader(vertex_entry_point.unwrap(), ShaderSpecializationConstants {
|
||||
first_constant: 0,
|
||||
second_constant: 0,
|
||||
third_constant: 0.0,
|
||||
@@ -234,7 +297,7 @@ impl GenericShader {
|
||||
// Use a resizable viewport set to draw over the entire window
|
||||
.viewports_dynamic_scissors_irrelevant(1)
|
||||
|
||||
.fragment_shader(frag_entry_point.clone().unwrap(), ShaderSpecializationConstants {
|
||||
.fragment_shader(fragment_entry_point.unwrap(), ShaderSpecializationConstants {
|
||||
first_constant: 0,
|
||||
second_constant: 0,
|
||||
third_constant: 0.0,
|
||||
@@ -242,6 +305,7 @@ impl GenericShader {
|
||||
|
||||
.depth_stencil(stencil)
|
||||
|
||||
|
||||
// We have to indicate which subpass of which render pass this pipeline is going to be used
|
||||
// in. The pipeline will only be usable from this particular subpass.
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use vulkano::buffer::{BufferAccess, BufferUsage, ImmutableBuffer, CpuAccessibleBuffer};
|
||||
use std::sync::Arc;
|
||||
use vulkano::format::{ClearValue, Format, R8Unorm};
|
||||
@@ -21,7 +21,7 @@ use vulkano::descriptor::descriptor::DescriptorDescTy::TexelBuffer;
|
||||
use crate::canvas::canvas_frame::CanvasFrame;
|
||||
use std::hash::Hash;
|
||||
use crate::canvas::canvas_text::{CanvasText, CanvasTextHandle};
|
||||
use crate::canvas::canvas_shader::{GenericShader, CanvasShaderHandle, CompiledGraphicsPipelineHandle, CompiledGraphicsPipeline};
|
||||
use crate::canvas::canvas_shader::{GenericShader, CanvasShaderHandle, CompiledGraphicsPipelineHandle, CompiledGraphicsPipeline, ShaderType};
|
||||
use crate::canvas::canvas_buffer::{CanvasImage, CanvasTexture, CanvasTextCache};
|
||||
use crate::util::vertex_3d::Vertex3D;
|
||||
use vulkano::pipeline::depth_stencil::{StencilFaceFlags, DynamicStencilValue};
|
||||
@@ -51,14 +51,6 @@ pub trait Drawable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Legacy ShaderType enum for single type shaders.
|
||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
pub enum ShaderType {
|
||||
SOLID = 0,
|
||||
TEXTURED = 1,
|
||||
IMAGE = 2,
|
||||
}
|
||||
|
||||
/// Typed wrapper for a u32 texture handle (index id)
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub struct CanvasTextureHandle {
|
||||
@@ -344,7 +336,6 @@ impl CanvasState {
|
||||
/// Takes physical and capabilities as we don't store that in Canvas
|
||||
pub fn load_shader(&mut self,
|
||||
filename: String,
|
||||
shader_type: ShaderType,
|
||||
physical: PhysicalDevice,
|
||||
capabilities: Capabilities) -> Option<Arc<CompiledGraphicsPipelineHandle>> {
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use vulkano::descriptor::pipeline_layout::PipelineLayout;
|
||||
use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet, PersistentDescriptorSetBuf};
|
||||
use image::ImageBuffer;
|
||||
use image::Rgba;
|
||||
use shade_runner::Layout;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub struct CompuBufferHandle {
|
||||
@@ -68,8 +69,8 @@ impl CompuBuffers {
|
||||
self.dimensions
|
||||
}
|
||||
|
||||
pub fn get_descriptor_set(&self, compute_pipeline: std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>>)
|
||||
-> Arc<PersistentDescriptorSet<std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>>, ((((),
|
||||
pub fn get_descriptor_set(&self, compute_pipeline: std::sync::Arc<ComputePipeline<PipelineLayout<Layout>>>)
|
||||
-> Arc<PersistentDescriptorSet<std::sync::Arc<ComputePipeline<PipelineLayout<Layout>>>, ((((),
|
||||
PersistentDescriptorSetBuf<std::sync::Arc<vulkano::buffer::cpu_access::CpuAccessibleBuffer<[u8]>>>),
|
||||
PersistentDescriptorSetBuf<std::sync::Arc<vulkano::buffer::cpu_access::CpuAccessibleBuffer<[u8]>>>),
|
||||
PersistentDescriptorSetBuf<std::sync::Arc<vulkano::buffer::cpu_access::CpuAccessibleBuffer<[u32]>>>)>> {
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::ffi::CStr;
|
||||
use std::path::PathBuf;
|
||||
use shade_runner as sr;
|
||||
use vulkano::descriptor::pipeline_layout::PipelineLayout;
|
||||
use shade_runner::{CompileError, FragLayout, FragInput, FragOutput, VertInput, VertOutput, VertLayout, CompiledShaders, Entry};
|
||||
use shade_runner::{CompileError, Layout, Input, Output, CompiledShaders, Entry, CompiledShader};
|
||||
use shaderc::CompileOptions;
|
||||
use vulkano::pipeline::shader::{ShaderModule, GraphicsEntryPoint, SpecializationConstants, SpecializationMapEntry};
|
||||
use crate::compute::compu_buffer::{CompuBuffers, CompuBufferHandle};
|
||||
@@ -20,12 +20,12 @@ pub struct CompuKernel {
|
||||
|
||||
handle: Arc<CompuKernelHandle>,
|
||||
|
||||
compute_pipeline: Option<std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>>>,
|
||||
compute_pipeline: Option<std::sync::Arc<ComputePipeline<PipelineLayout<Layout>>>>,
|
||||
compute_kernel_path: PathBuf,
|
||||
|
||||
name: String,
|
||||
|
||||
shader: CompiledShaders,
|
||||
shader: CompiledShader,
|
||||
entry: Entry,
|
||||
shader_module: Arc<ShaderModule>,
|
||||
device: Arc<Device>,
|
||||
@@ -61,7 +61,7 @@ impl CompuKernel {
|
||||
.expect("Failed to parse");
|
||||
|
||||
let shader_module = unsafe {
|
||||
vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.compute)
|
||||
vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.spriv)
|
||||
}.unwrap();
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ impl CompuKernel {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pipeline(&mut self) -> std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>> {
|
||||
pub fn get_pipeline(&mut self) -> std::sync::Arc<ComputePipeline<PipelineLayout<Layout>>> {
|
||||
|
||||
match self.compute_pipeline.clone() {
|
||||
Some(t) => t,
|
||||
@@ -91,7 +91,7 @@ impl CompuKernel {
|
||||
unsafe {
|
||||
ComputePipeline::new(self.device.clone(), &self.shader_module.compute_entry_point(
|
||||
CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||
self.entry.compute_layout.clone()), &self.specialization_constants,
|
||||
self.entry.layout.clone()), &self.specialization_constants,
|
||||
).unwrap()
|
||||
}
|
||||
}));
|
||||
@@ -100,11 +100,11 @@ impl CompuKernel {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recompile_kernel(&mut self) -> std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>> {
|
||||
pub fn recompile_kernel(&mut self) -> std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::Layout>>> {
|
||||
self.compile_kernel(String::from(self.compute_kernel_path.clone().to_str().unwrap()))
|
||||
}
|
||||
|
||||
pub fn compile_kernel(&mut self, filename: String) -> std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>> {
|
||||
pub fn compile_kernel(&mut self, filename: String) -> std::sync::Arc<ComputePipeline<PipelineLayout<Layout>>> {
|
||||
|
||||
let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap();
|
||||
self.compute_kernel_path = CompuKernel::get_path(filename);
|
||||
@@ -118,7 +118,7 @@ impl CompuKernel {
|
||||
.expect("Failed to parse");
|
||||
|
||||
self.shader_module = unsafe {
|
||||
vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &self.shader.compute)
|
||||
vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &self.shader.spriv)
|
||||
}.unwrap();
|
||||
|
||||
self.get_pipeline()
|
||||
|
||||
@@ -11,12 +11,12 @@ use winit::Window;
|
||||
use crate::compute::compu_state::CompuState;
|
||||
use vulkano::image::ImageUsage;
|
||||
use crate::compute::compu_frame::CompuFrame;
|
||||
use crate::canvas::canvas_state::{CanvasState, CanvasTextureHandle, CanvasImageHandle, ShaderType};
|
||||
use crate::canvas::canvas_state::{CanvasState, CanvasTextureHandle, CanvasImageHandle};
|
||||
use crate::canvas::canvas_frame::CanvasFrame;
|
||||
use crate::compute::compu_kernel::{CompuKernel, CompuKernelHandle};
|
||||
use crate::compute::compu_buffer::{CompuBuffers, CompuBufferHandle};
|
||||
use std::time::Duration;
|
||||
use crate::canvas::canvas_shader::{CanvasShaderHandle, CompiledGraphicsPipeline, CompiledGraphicsPipelineHandle};
|
||||
use crate::canvas::canvas_shader::{CanvasShaderHandle, CompiledGraphicsPipeline, CompiledGraphicsPipelineHandle, ShaderType};
|
||||
use vulkano::pipeline::depth_stencil::{DynamicStencilValue, StencilFaceFlags};
|
||||
|
||||
/// VKProcessor holds the vulkan instance information, the swapchain, and the compute and canvas states
|
||||
@@ -155,9 +155,9 @@ impl<'a> VkProcessor<'a> {
|
||||
|
||||
/// A hardcoded list of shaders which can be proloaded from this function
|
||||
pub fn preload_shaders(&mut self) {
|
||||
self.canvas.load_shader(String::from("color-passthrough"), ShaderType::SOLID, self.physical.clone(), self.capabilities.clone());
|
||||
self.canvas.load_shader(String::from("simple_texture"), ShaderType::TEXTURED, self.physical.clone(), self.capabilities.clone());
|
||||
self.canvas.load_shader(String::from("simple_image"), ShaderType::IMAGE, self.physical.clone(), self.capabilities.clone());
|
||||
self.canvas.load_shader(String::from("color-passthrough"), self.physical.clone(), self.capabilities.clone());
|
||||
self.canvas.load_shader(String::from("simple_texture"), self.physical.clone(), self.capabilities.clone());
|
||||
self.canvas.load_shader(String::from("simple_image"), self.physical.clone(), self.capabilities.clone());
|
||||
}
|
||||
|
||||
/// O(n) Lookup for the matching texture string
|
||||
|
||||
Reference in New Issue
Block a user