onsdag 28 september 2011

Win32 - Redirecting stdout, stderr and/or stdin of a child process.

I am currently working on a plugin for my asset conditioning pipeline (VACP) that compiles HLSL (High Level Shader Language).
The plugin works in the way that it simply looks up the location of the DirectX SDK from the environment variable DXSDK_DIR and executes the utility fxc.exe on the given asset.
My problem in all this was when something goes wrong during shader compilation, I need to propagate the error message up to VACP.The fxc.exe utility outputs information to the standard error stream (stderr), so how would I do to get this information into a std::string or similar?
 The solution was to use anonymous pipes to redirect the streams.

First, create your anonymous pipe:
SECURITY_ATTRIBUTES sec_attr;
sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
sec_attr.bInheritHandle = TRUE;
sec_attr.lpSecurityDescriptor = NULL;

if(!CreatePipe(this->fxc_stderr_rd, this->fxc_stderr_wr, &sec_attr, 0))
{
    return -1;
}

Here, fxc_stderr_rd is the HANDLE to the read "end" of the pipe, and fxc_stderr_wr is the HANDLE to the write "end" of the pipe.

Note that bInheritHandle of the SECURITY_ATTRIBUTES struct needs to be set to TRUE, or else you'll get smacked in the face with ERROR_BROKEN_PIPE once you try to read/write from the pipe. Not nice.

After the pipe handles has been created, call SetHandleInformation to make sure the read handle for the stderr is not inherited by the child process:

if(!SetHandleInformation(this->fxc_stderr_rd, HANDLE_FLAG_INHERIT, 0))
{
    CloseHandle(this->fxc_stderr_rd);
    CloseHandle(this->fxc_stderr_wr);
    return -1;
}

Time to create our child process and tell it to redirect its stderr stream to our pipe:

STARTUPINFO startup_info;
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(STARTUPINFO);
startup_info.dwFlags |= STARTF_USESTDHANDLES;
startup_info.hStdError = this->fxc_stderr_wr;

PROCESS_INFORMATION proc_info;
ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
        
if(!CreateProcess(
    const_cast<LPCWSTR>(fxc_path.c_str()),
    const_cast<LPWSTR>(fxc_args.c_str()),
    NULL,
    NULL,
    TRUE,
    0,
    NULL,
    NULL,
    &startup_info,
    &proc_info))
{
    CloseHandle(this->fxc_stderr_rd);
    CloseHandle(this->fxc_stderr_wr);

    std::wstringstream msg_stream;
    msg_stream << L"CreateProcess failed. Return value: " << GetLastError();
    ContentCompiler::set_last_error_msg(msg_stream.str());
    return -1;
}

The interesting part here is what we do just in the beginning of this code snippet.
In the STARTUPINFO struct, setting the STARTF_USESTD_ERROR_HANDLE flag on the dwFlags member will tell CreateProcess to examine the hStdError, hStdInput and hStdOutput members for handles to redirect the streams to. In this case I am only interested in the stderr stream.
The next line effectively redirects the standard error stream to the write handle of our pipe!

Once the fxc.exe has been invoked as our child process, we'll just wait until it has finished compilation by using WaitForSingleObject, after which we examine the exit code of the process aswell as close our handles:

WaitForSingleObject(proc_info.hThread, COMPILE_TIMEOUT);

DWORD exit_code;
GetExitCodeProcess(proc_info.hProcess, &exit_code);

CloseHandle(proc_info.hProcess);
CloseHandle(proc_info.hThread);
CloseHandle(this->fxc_stderr_wr);


This effectively closes the handles to our child process and its main thread, aswell as the handle to the write end of our anonymous pipe, which we do not need anymore. It is not time to dispose the read handle just yet...

fxc.exe, following the norms of exit codes, returns non-zero on failure. If exit_code is non-zero, we should examine the contents of the pipe.
if(exit_code != 0)
{
    std::string error_info = this->get_pipe_data();
    ContentCompiler::set_last_error_msg(error_info);
    return -1;
}

Where get_pipe_data is defined as:
const std::string HLSLCompiler::get_pipe_data()
{
    std::string error_info;
    char buffer[READ_BUFF_SIZE];
    DWORD bytes_read;

    while(ReadFile(this->fxc_stderr_rd, buffer, READ_BUFF_SIZE, &bytes_read, NULL) && bytes_read > 0)
    {
        error_info.append(buffer, bytes_read);
    }

    return error_info;
}

And there you go!

There will probably be an angry mob screaming at me (or not so much!) for only showing how to redirect stderr when the title of this post promised oh so much more. It would be practically the same with stdin and stdout, I promise.

The code snippets are taken directly from my project so i apologize if the look like they're taken a bit out of context ...because they are! The code is also fairly fresh so I haven't gotten proper error handling or cleanup yet. Do not despair, it'll be there soon! And it'll be checked in to the repository too, oh fun!

måndag 15 augusti 2011

When to forward declare?

Ok. I have just realized that the structure of my source code files isnt very good at all. Ok, I didnt just realize it, I have known it for a while. But I havent bothered to fix it until now. First thing I'm doing is making sure that each class is contained in its own header file. Next up I'm going to separate my project into logical parts, which will serve as namespaces.
Im going to fix the directory structure aswell,to reflect the namespaces in the project.

My concern is; When should one forward declare a type?
Take the vtx_render.h (soon to be renamed to vtx_rendermanager.h!) for instance, which contains the following:

#ifndef VTX_RENDER_H
#define VTX_RENDER_H

// ...
#include <vortex/vtx_window.h>


class RenderManager : VortexBase
{
public:
        RenderManager(Root&);
        void init(RenderCreationParams &params, WindowCreationParams &windowParams);
        void destroy(void);
        RenderAPI *getRenderObject(void);
private:
        void createWindow(WindowCreationParams &params);
        NativeWindow *window;
        bool manageWindow;
        RenderAPI *render;
};


#endif

Notice that WindowCreationParams used as input parameter to the init and createWindow methods. The class WindowCreationParams is defined in vtx_window.h

Since our limited use of WindowCreationParams, we do not need the entire definition of the class and so the include of vtx_window isn't really necessary. I can just forward declare WindowCreationParams:

#ifndef VTX_RENDER_H
#define VTX_RENDER_H

// ...
class WindowCreationParams;


class RenderManager : VortexBase
{
public:
        RenderManager(Root&);
        void init(RenderCreationParams &params, WindowCreationParams &windowParams);
        void destroy(void);
        RenderAPI *getRenderObject(void);
private:
        void createWindow(WindowCreationParams &params);
        NativeWindow *window;
        bool manageWindow;
        RenderAPI *render;
};


#endif

The pros for this include:
  • Improved compilation time.
  • Reduces risk of cyclic dependency.
  • ... possibly something else I'm not thinking about.
The cons:
  •  If the class being forward declared is removed or renamed, the header using the forward declaration will  not be affected, instead the error will not show until in the source files including this header.
  • Semi-related to the above point; having to keep all forward declarations up to date concerning class name/containing namespace.
  •  Template classes can not be forward declared (?) This is not really an issue per se, just a restriction (that is easy to work around!).
  •  ... possibly something else I'm not thinking about ;)
I know no one is reading this, but I would still appreciate your input!

(Edit: I forgot to say, I intend to use forward declarations whenever possible, unless I find a good reason not to!)

lördag 13 augusti 2011

SIMD Vector normalization.

I've begun to work on one of the Camera classes in the engine, and when thinking about how to create my view matrices I found that I do not yet have any methods for normalizing my 3D vectors. Normalizing a vector is just about finding the length of the vector and then dividing each element of the vector by it:

Vnorm = V / |V|

Now I figured I'd do this with SIMD because I need all the speed I can get (but of course, optimizations are not top priority this early on!)
Here's what I came up with

void Vector3::normalize(void)
{
    // Must pad with a trailing 0, to store in 128-bit register
    ALIGNED_16 platform::F32_t vector[] = {this->x, this->y, this->z, 0};
    __m128 simdvector;
    __m128 result;
    simdvector = _mm_load_ps(vector);
    
    // (X^2, Y^2, Z^2, 0^2)
    result = _mm_mul_ps(simdvector, simdvector);

    // Add all elements together, giving us (X^2 + Y^2 + Z^2 + 0^2)
    result = _mm_hadd_ps(result, result);
    result = _mm_hadd_ps(result, result);
    
    // Calculate square root, giving us sqrt(X^2 + Y^2 + Z^2 + 0^2)
    result = _mm_sqrt_ps(result);

    // Calculate reciprocal, giving us 1 / sqrt(X^2 + Y^2 + Z^2 + 0^2)
    result = _mm_rcp_ps(result);

    // Finally, multiply the result with our original vector.
    simdvector = _mm_mul_ps(simdvector, result);

    _mm_store_ps(vector, simdvector);

    this->x = vector[0];
    this->y = vector[1];
    this->z = vector[2];
}

What I'm worried about though is that I might be loosing precision when using floats to calculate the normalized vector. For instance, XNA uses doubles for the intermediate calculations, but stores the result as a float. I tried normalizing the same vector in my engine and in XNA, and noticed slightly varying results. Nothing big, but by the 4th or 5th decimal, the normalized vectors would differ.

Does anyone have any input on this? Can I keep it as is? Or should I use two __m128 registers storing two 64-bit values each (instead of one __m128 storing 4x 32 bit values as I currently do). This would double the number of intrinsics in my code, but give me better precision.

(Thanks Andrew for helping me with the subscript formatting!)

onsdag 10 augusti 2011

Declaration does not declare anything.

This was new to me.
I had just set up Fedora (virtual machine) to use for linux development on my new computer. I checked out my source code through svn and tried to build it and the above warning shows up. Whats more, its pointing to one of the typedefs I wrote waaay back, and has compiled fine with g++ / msvc 2010 before. In fact, it still compiled well in msvc, the only one having the problem is g++.

The offending line of code was this:

vtx_atomic.h
typedef float F32;

And this in turn caused another problem!
I reference this F32 declaration from many places in my code, but there is one specific location where I use F32 as a template argument for a class, and thats where it freaked out.
The code looks like the following:

vtx_vbuffer.h
struct VertexPosNormTex
{
    core::Vector3 position;
    core::Vector3 normal;
    core::Vector2<platform::F32> texCoord;
};

It resulted in the error:
../include/vortex/vtx_vbuffer.h:11:31: error: template argument 1 is invalid

I renamed the typedef and all warnings and errors went away. Is F32 conflicting with something? If it is, how come it didn't do that earlier?


måndag 8 augusti 2011

VACP

Part of my offline processing tools for the engine is vacp. Awkward abbreviation, I know. It stands for Vortex Asset Conditioning Pipeline. It's job is to process content (aka assets) to be consumed by the engine, so that they need little to no further processing at runtime by the engine.
When processed by vacp, each asset is first exported using a particular content exporter, and the output from this stage is fed to the content compiler, which in turn produces the engine-ready file.
When vacp is first invoked, it first registers the exporters and compilers has available by scanning libraries in a predefined plugin folder. This enables a developer to, for example, write a PNG exporter to allow the use of PNGs as textures in the engine, or write their own implementation of a content compiler more suitable for their needs.

Right now, I've just semi-finished a BMP exporter and a DDS (DirectDraw Surface) compiler. This means that bitmaps can be fed into vacp, and it will output a dds file (provided that the asset in question is set up to use this exporter and compiler, that is)... its pretty neat, but it is also the only thing vacp can do at the moment :) I'll post more on that subject tomorrow!

First post!

So this is my new "blog" (more like project diary) where I'll be making posts about my progress in creating a game engine, or atleast something close to it ;).

The project is open source and hosted on Google Code and is split up into two repositories. The first one contains the engine and can be found here. The second one contains a set of tools that goes under the name of Maelstrom, which will be used to develop games for the engine. It can be found here.


As stated on the Vortex engine repository main page:
The main goal with this project is not to create something that is state-of-the-art or superior to any other free open-source engine out there. The goal is just to create a fully functional game engine from the ground up, and learn alot from the process. 
 
I know that people don't read blogs like these, but I hope I can attract someones interest!