Premake5: How to build HLSL shaders? - hlsl

I'm struggling to figure out how to set up my hlsl shaders to work with Premake5 and Visual Studio 2017.
I have no idea how to tell Premake5 to compile my hlsl shaders, as a pre-build step.
Here are my goals for this pre-build step:
Specify shader model
Specify debug/release compilation
Only compile files that have changed
Produce dxasm files
Place resulting *.asms and *.cso in appropriate release/debug folders
Update 1:
Investigating a little further I found that Premake5 has buildaction which makes direct reference to FxCompile.
Update 2:
Thanks to mukunda. I was able to configure my project perfectly!
I had to build premake5 from source in order to get this premake script to run.
Because as of March, 2019 the binary distributed doesn't support shader model greater than 5.
hf.deactivate_filter()
files(src_dir.."shaders/*.hlsl")
shadermodel("6.3")
shaderassembler("AssemblyCode")
local shader_dir = _WORKING_DIR.."/"..src_dir.."shaders/%{cfg.buildcfg}/"
-- HLSL files that don't end with 'Extensions' will be ignored as they will be
-- used as includes
filter("files:**.hlsl")
flags("ExcludeFromBuild")
shaderobjectfileoutput(shader_dir.."%{file.basename}"..".cso")
shaderassembleroutput(shader_dir.."%{file.basename}"..".asm")
filter("files:**_ps.hlsl")
removeflags("ExcludeFromBuild")
shadertype("Pixel")
filter("files:**_vs.hlsl")
removeflags("ExcludeFromBuild")
shadertype("Vertex")
hf.deactivate_filter()
-- Warnings as errors
shaderoptions({"/WX"})
Update 3:
I figured out how to handle command line parameters.

I was just messing around with this today. For my HLSL files I have a simple naming scheme:
*-p.hlsl for pixel shader files.
*-v.hlsl for vertex shader files.
*.hlsl for generic files meant to be included by the shader programs. I just use the hlsl extension so that it shows up with proper HLSL syntax highlighting in the editor.
You don't need custom build rules to compile them. Premake seems to be able to output a proper block in the Visual Studio project for using the shader compiler, and then things like only recompiling files that have changed (with #include dependencies) are handled just fine. Here's what my configuration block looks like:
filter { "files:**.hlsl" }
flags "ExcludeFromBuild"
shadermodel "5.0"
filter { "files:**-p.hlsl" }
removeflags "ExcludeFromBuild"
shadertype "Pixel"
shaderentry "ForPixel"
filter { "files:**-v.hlsl" }
removeflags "ExcludeFromBuild"
shadertype "Vertex"
shaderentry "ForVertex"
filter {}
Basically sets up the shadermodel and entry points for my files (For DirectX 12 you probably want shadermodel "6.0"). Then I can add my shaders to the project through files:
files { "shaders/**.hlsl"; }
This is all very new stuff in premake, so you won't find much documentation on it. I saw these options here: https://github.com/premake/premake-core/blob/master/modules/vstudio/_preload.lua.
As for your question about exporting the dxasm files, there are some other options such as shaderassembleroutput and shaderassembler, the latter I believe to be the switch that exports the assembly code to the location specified, but I have not done any testing with these to give an elaborate answer.
Unfortunately I'm not really sure how to enable debugging information in the output files, as there doesn't seem to be a premake option for that yet. I was digging through the documentation to look for any way to add the /Zi (enable debug symbols) flag for shader compilation, but I'm not entirely sure if it's possible.

Related

Why can't Visual Studio find my main function once I add an hlsl/fx file?

Sidenode: I'm not asking anyone to help me with a directx tutorial. I think this error is a normal Visual Studio win32 API error.
Hey guys and girls,
I'm trying to learn some DirectX 11 for fun and I found those directx11 examples on github. Now I'm trying to understand each function and see how everything works together. I created a new VS project just to play around with stuff. I copy-pasted all of the code in Tutorial02.cpp into my own project, created a new filter called "Shaders" and changed the properties of my VS solution. At that point I don't have any problems to compile my code. Once I add the Tutorial02.fx, Tutorial02_VS.hlsl and Tutorial02_PS.hlsl to the solution VS can't compile and gives me the following error code:
X3501 'main': entrypoint not found Project00 C:\Users\Meow\Desktop\directx-tests\Project00\Project00\Project00\FXC 1
Github link (directx11 tutorial main file):https://github.com/walbourn/directx-sdk-samples/blob/master/Direct3D11Tutorials/Tutorial02/Tutorial02.cpp
What I did:
I created a new VS project called Project00 in my directx-tests folder
I created a new file called Source.cpp
I copy-pasted everything from Tutorial02.ccp (github) into my Source.cpp
I added the resource.h file to my project
I added under "Project00 -> Properties -> Linker -> Input" the same libs as the tutorial
d3d11.lib
d3dcompiler.lib
dxguid.lib
winmm.lib
comctl32.lib
I changed under "Properties -> Link -> System" the SubSystem to Windows(:SUBSYSTEM/WINDOWS)
I copy-pasted the .hlsl and .fx file/s into my project directory (didn't add it to the VS solution yet)
At that point it works just fine. It compiles without a problem.
But when I add the Tutorial02.fx, Tutorial02_VS.hlsl and Tutorial02_PS.hlsl to my Shader filter or any other filter and recompile visual studio tells me: 'main': entrypoint not found -- Once I remove (not delete) the files again it works just fine.
Does anyone know why?
(In the tutorial solution they add these files to the solution aswell and it works just fine)
With the help of github demo, I can reproduce this problem. You can refer to the screenshots below to modify:
Tutorial02.fx properties:
Tutorial02_PS.hlsl properties:
Tutorial02_VS.hlsl properties:
You can also refer HLSL Property Pages to learn how individual HLSL shader files are built.

CMake: How to add a .obj 3d models to C++ Visual Studio UWP project

I'm trying to add a 3d model to the resources of an Appx in a cmake build. I have it successfully working with most formats, but files ending in .obj are being treated as compiled object files.
The cmake Visual Studio generator seems to always treat any file with an extension .obj as an object file and adds it to the vcxproj with the tag.
Is there a way to change the internal type of a file that cmake is using? Can I specify that this file is NOT an "EXTERNAL_OBJECT"?
Setting the VS_DEPLOYMENT_CONTENT to 1 doesn't help.
Adding it to the RESOURCES property doesn't help.
It looks like it might be an issue in the cmake source code itself where it checks if a file type if EXTERNAL_OBJECT before checking any other flags or types, and I can't figure out how to unset that type.
As per this issue on the cmake gitlab repo https://gitlab.kitware.com/cmake/cmake/issues/18820, there is a hacky fix solution but no "correct" fix yet.
Brad King:
As a very hacky not very futureproof workaround that abuses current implementation details, try:
get_property(loc SOURCE myfile.obj PROPERTY LOCATION)
set_property(SOURCE myfile.obj PROPERTY EXTERNAL_OBJECT 0)
The first line forces this code and therefore this code to run, causing CMake to initialize the EXTERNAL_OBJECT property earlier than it normally would. Once that is done then we can set the property back to 0.
A possible fix would be to teach the latter code (in CheckExtension) to not set the EXTERNAL_OBJECT property if it is already set. We can't change the default behavior of treating .obj files as objects to link, but we can at least make an explicit property setting work without the above hack.
I have confirmed that this works for the .obj files in our solution.

Get .stl format 3D mesh from Binary Mask (Segmentation)

I am currently able to get mesh files of these formats however I would like to save the mesh file as .stl. I found documentation about this STL MeshIO Class, however, I can't seem to find the header to "include".
Additionally, if I follow from this, it still asks me to enter proper file extension, as in it doesn't work when I give .stl extension.
Any help or work around?
P.S. ITK-4.11.0, VS 13 Update 5, CMake - 3.8.0.
Let me know if you need the code, I don't see a requirement here.
Just adding the procedure here for someone who might be interested.
Get git executable.
In CMake go to advanced and add the path to the git executable
In Modules, add Module_IOSTL
Configure and Generate.
Build the ITK.sln file. (If using VS)
Configure and Generate your project.
Add #include "itkSTLMeshIOFactory.h"
Add itk::STLMeshIOFactory::RegisterOneFactory(); before you initialize the MeshType.
Give file extension for MeshFileWriter as .stl, and voila!
IOSTL is a remote module. When configuring ITK with CMake, you need to enable Module_IOSTL in group Module. Rebuild ITK, rebuild your program, and now you should be able to read and write .stl just the same as .vtk, .off etc. Hopefully, without any code changes.

Creating .fxo shader file using fxc.exe

Does anybody know how to compile a single file containing various shaders (PixelShader, VertexShader, GeometryShader) using the fxc.exe tool provided by the DirectX 11 SDK?
The shader is used to create a tesselation-effect in a C++ programmed Enviroment:
The result should be a .fxo shader File.
Thx in advance :)
You run the compiler separately for each effect source file (one source file per effect, including the various shaders and helper routines). There will be a separate shader object file for each effect, similarly. The command line depends on what you actually want to compile but something like this:
fxc.exe /T ps_2_0 /nologo /E main /Fo"Effect.fxo" "Effect.fx"
or
fxc.exe /T fx_4_0 /nologo /Fo"Effect.fxo" "Effect.fx"

How to get a python .pyd for Windows from c/c++ source code? (update: brisk now in Python in case that's what you want)

How to get from C/C++ extension source code to a pyd file for windows (or other item that I could import to Python)?
edit: The specific library that I wanted to use (BRISK) was included in OpenCV 2.4.3 so my need for this skill went away for the time being. In case you came here looking for BRISK, here is a simple BRISK in Python demo that I posted.
I have the Brisk source code (download) that I would like to build and use in my python application. I got as far as generating a brisk.pyd file... but it was 0 bytes. If there is a better / alternative way to aiming for a brisk.pyd file, then of course I am open to that as well.
edit: Please ignore all the attempts in my original question below and see my answer which was made possible by obmarg's detailed walkthrough
Where am I going wrong?
Distutils without library path: First I tried to build the source as is with distutils and the following setup.py (I have just started learning distutils so this is a shot in the dark). The structure of the BRISK source code is at the bottom of this question for reference.
from distutils.core import setup, Extension
module1 = Extension('brisk',
include_dirs = ['include', 'C:/opencv2.4/build/include', 'C:/brisk/thirdparty/agast/include'],
#libraries = ['agast_static', 'brisk_static'],
#library_dirs = ['win32/lib'],
sources = ['src/brisk.cpp'])
setup (name = 'BriskPackage',
ext_modules = [module1])
That instantly gave me the following lines and a 0 byte brisk.pyd somewhere in the build folder. So close?
running build
running build_ext
Distutils with library path: Scratch that attempt. So I added the two library lines that are commented out in the above setup.py. That seemed to go ok until I got this linking error:
creating build\lib.win32-2.7
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:win32/lib /LIB
PATH:C:\Python27_32bit\libs /LIBPATH:C:\Python27_32bit\PCbuild agast_static.lib brisk_static.lib /EXPORT:initbrisk build
\temp.win32-2.7\Release\src/brisk.obj /OUT:build\lib.win32-2.7\brisk.pyd /IMPLIB:build\temp.win32-2.7\Release\src\brisk.
lib /MANIFESTFILE:build\temp.win32-2.7\Release\src\brisk.pyd.manifest
LINK : error LNK2001: unresolved external symbol initbrisk
build\temp.win32-2.7\Release\src\brisk.lib : fatal error LNK1120: 1 unresolved externals
error: command '"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\link.exe"' failed with exit status 1120
Uncontrolled flailing: I thought maybe the libraries needed to be built, so I did a crash course (lots of crashing) with cmake + mingw - mingw + vc++ express 2010 as follows:
cmake gui: source: c:/brisk, build: c:/brisk/build
cmake gui: configure for Visual Studio 10
cmake gui: use default options and generate (CMAKE_BACKWARDS_COMPATIBILITY, CMAKE_INSTALL_PREFIX, EXECUTABLE_OUTPUT_PATH, LIBRARY_OUTPUT_PATH)
VC++ Express 10: Change to Release and build the solution generated by cmake and get about 20 pages of what look like non-critical warnings followed by all succeeded. Note - no dlls are generated by this. It does generate the following libraries of similar size to the ones included with the download:
win32/lib/Release/
agast_static.lib
brisk_static.lib
Further flailing.
Relevant BRISK source file structure for reference:
build/ (empty)
include/brisk/
brisk.h
hammingsse.hpp
src
brisk.cpp
demo.cpp
thirdparty/agast/
include/agast/
agast5_8.h ....
cvWrapper.h
src/
agast5_8.cc ...
CMakeLists.txt
win32/
bin/
brisk.mexw32
opencv_calib3d220.dll ...
lib/
agast_static.lib
brisk_static.lib
CMakeLists.txt
FindOpenCV.cmake
Makefile
Are you sure that this brisk library even exports python bindings? I can't see any reference to it in the source code - it doesn't even seem to import python header files. This would certainly explain why you've not had much success so far - you can't just compile plain C++ code and expect python to interface with it.
I think your second distutils example is closest to correct - it's obviously compiling things and getting to the linker stage, but then you encounter this error. That error just means it can't find a function named initbrisk which I'm guessing would be the top level init function for the module. Again this suggests that you're trying to compile a python module from code that isn't meant for it.
If you want to wrap the C++ code in a python wrapper yourself you could have a look at the official documentation on writing c/c++ extensions. Alternatively you could have a look into boost::python, SIP or shiboken which try to somewhat (or completely) automate the process of making python extensions from C++ code.
EDIT: Since you seem to have made a decent amount of effort to solve the problem yourself and have posted a good question, I've decided to give a more detailed response on how to go about doing this.
Quick Tutorial On Wrapping C++ Libraries Using boost::python
Personally I've only ever used boost::python for stuff like this, so I'll try and give you a good summary of how to go about doing that. I'm going to assume that you're using Visual C++ 2010. I'm also going to assume that you've got a 32bit version of python installed, as I believe the boost pro libraries only provide 32bit binaries.
Installing boost
First you'll need to grab a copy of the boost library. The easiest way to do this is to download an installer from the boost pro website. These should install all the header files and binary files that are required for using the boost c++ library on windows. Take note of where you install these files to, as you'll need them later on - it might be best to install to a path without a space in it. For easyness I'm going to assume you put these files in C:\boost but you can substitute that for the path you actually used.
Alternatively, you can follow these instructions to build boost from source. I'm not 100% sure, but it might be the case that you need to do this in order to get a version of boost::python that is compatible with the version of python you have installed.
Setting up a visual studio project
Next, you'll want to setup a visual studio project for brisk.pyd. If you open visual studio, go to New -> Project then find the option for Win32 Project. Set up your location etc. and click ok. In the wizard that appears select a DLL project type, and then tick the empty project checkbox.
Now that you've created your project, you'll need to set up the include & library paths to allow you to use python, boost::python and the brisk.lib file.
In Visual Studios solution explorer, right click on your project, and select properties from the menu that appears. This should open up the property pages for your project. Go to the Linker -> General section and look for the Additional Library Directories section. You'll need to fill this in with the paths to the .lib files for boost, python and your brisk_static.lib. Generally these can be found in lib (or libs) subdirectories of
wherever you've installed the libraries. Paths are seperated with semicolons. I've attached a screenshot of my settings below:
Next, you'll need to get visual studio to link to the .lib files. These sections can be found in the Additional Dependencies field of the Linker -> Input section of the properties. Again it's a semicolon delimited list. You should need to add in libraries for python (in my case this is python27.lib but this will vary by version) and brisk_static.lib. These do not require the full path as you added that in the previous stage. Again, here's a screenshot:
You may also need to add the boost_python library file but I think boost uses some header file magic to save you the trouble. If I'm incorrect then have a look in you boost library path for a file named similar to boost_python-vc100-mt.lib and add that in.
Finally, you'll need to setup the include paths to allow your project to include the relevant C++ header files. To get the relevant settings to appear in project properties, you'll need to add a .cpp file to your project. Right click the source files folder in your solution explorer, and then go to add new item. Select a C++ File (.cpp) and name it main.cpp (or whatever else you want).
Next, go back to your project properties and go to C/C++ -> General. Under the additional libraries directory you need to add the include paths for brisk, python and boost. Again, semicolons for seperators, and again here's a screenshot:
I suspect that you might need to update these settings to include the opencv2 & agast libraries as well but I'll leave that as a task for you to figure out - it should be much the same process.
Wrapping existing c++ classes with boost::python.
Now comes the slightly trickier bit - actually writing C++ to wrap your brisk library in boost python. You can find a tutorial for this here but i'll try and go over it a bit as well.
This will be taking place in the main.cpp file you created earlier. First, add the relevant include statements you'll need at the top of the file:
#include <brisk/brisk.h>
#include <Python.h>
#include <boost/python.hpp>
Next, you'll need to declare your python module. I'm assuming you'd want this to be called brisk, so you do something like this:
BOOST_PYTHON_MODULE(brisk)
{
}
This should tell boost::python to create a python module named brisk.
Next it's just a case of going through all the classes & structs that you want to wrap and declaring boost python classes with them. The declerations of the classes should all be contained in brisk.h. You should only wrap the public members of a class, not any protected or private members. As a quick example, I've done a couple of the structs here:
BOOST_PYTHON_MODULE(brisk)
{
using namespace boost::python;
class_< cv::BriskPatternPoint >( "BriskPatternPoint" )
.def_readwrite("x", &cv::BriskPatternPoint::x)
.def_readwrite("y", &cv::BriskPatternPoint::y)
.def_readwrite("sigma", &cv::BriskPatternPoint::sigma);
class< cv::BriskScaleSpace >( "BriskScaleSpace", init< uint8_t >() )
.def( "constructPyramid", &cv::BriskScaleSpace::constructPyramid );
}
Here I have wrapped the cv::BriskPatternPoint structure and the cv::BriskScaleSpace class. Some quick explanations:
class_< cv::BriskPatternPoint >( "BriskPatternPoint" ) tells boost::python to declare a class, using the cv::BriskPatternPoint C++ class, and expose it as BriskPatternPoint in python.
.def_readwrite("y", &cv::BriskPatternPoint::y) adds a readable & writeable property to the BriskPatternPoint class. The property is named y, and will map to the BriskPatternPoint::y c++ field.
class< cv::BriskScaleSpace >( "BriskScaleSpace", init< uint8_t >() ) declares another class, this time BriskScaleSpace but also provides a constructor that accepts a uint8_t (an unsigned byte - which should just map to an integer in python, but I'd be careful to not pass in one greater than 255 bytes - I don't know what would happen in that situation)
The following .def line just declares a function - boost::python should (I think) be able to determine the argument types of functions automatically, so you don't need to provide them.
It's probably worth noting that I haven't actually compiled any of these examples - they might well not work at all.
Anyway, to get this fully working in python it should just be a case of doing similar for every structure, class, property & function that you want accessible from python - which is potentially quite a time consuming task!
If you want to see another example of this in action, I did this here to wrap up this class
Building & using the extension
Visual studio should take care of building the extension - then using it is just a case of taking the .DLL and renaming it to .pyd (you can get VS to do this for you, but I'll leave that up to you).
Then you just need to copy your python file to somewhere on your python path (site-packages for example), import it and use it!
import brisk
patternPoint = brisk.BriskPatternPoint()
....
Anyway, I have spent a good hour or so writing this out - so I'm going to stop here. Apologies if I've left anything out or if anything isn't clear, but I'm doing this mostly from memory. Hopefully it's been of some help to you. If you need anything clarified please just leave a comment, or ask another question.
In case someone needs it, this what I have so far. Basically a BriskFeatureDetector that can be created in Python and then have detect called. Most of this is just confirming/copying what obmarg showed me, but I have added the details that get all the way to the pyd library.
The detect method is still incomplete for me though since it does not convert data types. Anyone who knows a good way to improve this, please do! I did find, for example, this library which seems to convert a numpy ndarray to a cv::Mat, but I don't have the time to figure out how to integrate it now. There are also other data types that need to be converted.
Install OpenCV 2.2
for the setup below, I installed to C:\opencv2.2
Something about the API or implementation has changed by version 2.4 that gave me problems (maybe the new Algorithm object?) so I stuck with 2.2 which BRISK was developed with.
Install Boost with Boost Python
for the setup below, I installed to C:\boost\boost_1_47
Create a Visual Studio 10 Project:
new project --> win32
for the setup below, I named it brisk
next --> DLL application type; empty project --> finished
at the top, change from Debug Win32 to Release Win32
Create main.cpp in Source Files
Do this before the project settings so the C++ options become available in the project settings
#include <boost/python.hpp>
#include <opencv2/opencv.hpp>
#include <brisk/brisk.h>
BOOST_PYTHON_MODULE(brisk)
{
using namespace boost::python;
//this long mess is the only way I could get the overloaded signatures to be accepted
void (cv::BriskFeatureDetector::*detect_1)(const cv::Mat&,
std::vector<cv::KeyPoint, std::allocator<cv::KeyPoint>>&,
const cv::Mat&) const
= &cv::BriskFeatureDetector::detect;
void (cv::BriskFeatureDetector::*detect_vector)(const std::vector<cv::Mat, std::allocator<cv::Mat>>&,
std::vector< std::vector< cv::KeyPoint, std::allocator<cv::KeyPoint>>, std::allocator< std::vector<cv::KeyPoint, std::allocator<cv::KeyPoint>>>>&,
const std::vector<cv::Mat, std::allocator<cv::Mat>>&) const
= &cv::BriskFeatureDetector::detect;
class_< cv::BriskFeatureDetector >( "BriskFeatureDetector", init<int, int>())
.def( "detect", detect_1)
;
}
Project Settings (right-click on the project --> properties):
Includes / Headers
Configuration Properties --> C/C++ --> General
add to Additional Include Directories (adjust to your own python / brisk / etc. base paths):
C:\opencv2.2\include;
C:\boost\boost_1_47;
C:\brisk\include;C:\brisk\thirdparty\agast\include;
C:\python27\include;
Libraries (linker)
Configuration Properties --> Linker --> General
add to Additional Library Directories (adjust to your own python / brisk / etc. base paths):
C:\opencv2.2\lib;
C:\boost\boost_1_47\lib;
C:\brisk\win32\lib;
C:\python27\Libs;
Configuration Properties --> Linker --> Input
add to Additional Dependencies (adjust to your own python / brisk / etc. base paths):
opencv_imgproc220.lib;opencv_core220.lib;opencv_features2d220.lib;
agast_static.lib; brisk_static.lib;
python27.lib;
.pyd output instead of .dll
Configuration Properties --> General
change Target Extension to .pyd
Build and rename if necessary
Right-click on the solution and build/rebuild
you may need to rename the output from "Brisk.pyd" to "brisk.pyd" or else python will give you errors about not being able to load the DLL
Make brisk.pyd available to python by putting it in site packages or by putting a .pth file that links to its path
Update Path environment variable
In windows settings, make sure the following are included in your path (again, adjust to your paths):
`C:\boost\boost_1_47\lib;C:\brisk\win32\bin`