Improved error reporting

This commit is contained in:
ZZYZX 2019-12-15 23:53:33 +02:00
parent 7f09dd2aec
commit 502b641967
8 changed files with 979 additions and 819 deletions

View file

@ -29,6 +29,11 @@ using System.Reflection;
namespace CodeImp.DoomBuilder.Rendering
{
public class RenderDeviceException : Exception
{
public RenderDeviceException(string message) : base(message) { }
}
public class RenderDevice : IDisposable
{
public RenderDevice(RenderTargetControl rendertarget)
@ -59,6 +64,13 @@ namespace CodeImp.DoomBuilder.Rendering
public bool Disposed { get { return Handle == IntPtr.Zero; } }
private void CheckAndThrow()
{
string err = Marshal.PtrToStringAnsi(RenderDevice_GetError(Handle));
if (err != "")
throw new RenderDeviceException(err);
}
public void Dispose()
{
if (!Disposed)
@ -71,36 +83,43 @@ namespace CodeImp.DoomBuilder.Rendering
public void SetShader(ShaderName shader)
{
RenderDevice_SetShader(Handle, shader);
CheckAndThrow();
}
public void SetUniform(UniformName uniform, bool value)
{
RenderDevice_SetUniform(Handle, uniform, new float[] { value ? 1.0f : 0.0f }, 1);
CheckAndThrow();
}
public void SetUniform(UniformName uniform, float value)
{
RenderDevice_SetUniform(Handle, uniform, new float[] { value }, 1);
CheckAndThrow();
}
public void SetUniform(UniformName uniform, Vector2 value)
{
RenderDevice_SetUniform(Handle, uniform, new float[] { value.X, value.Y }, 2);
CheckAndThrow();
}
public void SetUniform(UniformName uniform, Vector3 value)
{
RenderDevice_SetUniform(Handle, uniform, new float[] { value.X, value.Y, value.Z }, 3);
CheckAndThrow();
}
public void SetUniform(UniformName uniform, Vector4 value)
{
RenderDevice_SetUniform(Handle, uniform, new float[] { value.X, value.Y, value.Z, value.W }, 4);
CheckAndThrow();
}
public void SetUniform(UniformName uniform, Color4 value)
{
RenderDevice_SetUniform(Handle, uniform, new float[] { value.Red, value.Green, value.Blue, value.Alpha }, 4);
CheckAndThrow();
}
public void SetUniform(UniformName uniform, Matrix matrix)
@ -111,173 +130,207 @@ namespace CodeImp.DoomBuilder.Rendering
matrix.M31, matrix.M32, matrix.M33, matrix.M34,
matrix.M41, matrix.M42, matrix.M43, matrix.M44
}, 16);
CheckAndThrow();
}
public void SetVertexBuffer(VertexBuffer buffer)
{
RenderDevice_SetVertexBuffer(Handle, buffer != null ? buffer.Handle : IntPtr.Zero);
CheckAndThrow();
}
public void SetIndexBuffer(IndexBuffer buffer)
{
RenderDevice_SetIndexBuffer(Handle, buffer != null ? buffer.Handle : IntPtr.Zero);
CheckAndThrow();
}
public void SetAlphaBlendEnable(bool value)
{
RenderDevice_SetAlphaBlendEnable(Handle, value);
CheckAndThrow();
}
public void SetAlphaTestEnable(bool value)
{
RenderDevice_SetAlphaTestEnable(Handle, value);
CheckAndThrow();
}
public void SetCullMode(Cull mode)
{
RenderDevice_SetCullMode(Handle, mode);
CheckAndThrow();
}
public void SetBlendOperation(BlendOperation op)
{
RenderDevice_SetBlendOperation(Handle, op);
CheckAndThrow();
}
public void SetSourceBlend(Blend blend)
{
RenderDevice_SetSourceBlend(Handle, blend);
CheckAndThrow();
}
public void SetDestinationBlend(Blend blend)
{
RenderDevice_SetDestinationBlend(Handle, blend);
CheckAndThrow();
}
public void SetFillMode(FillMode mode)
{
RenderDevice_SetFillMode(Handle, mode);
CheckAndThrow();
}
public void SetMultisampleAntialias(bool value)
{
RenderDevice_SetMultisampleAntialias(Handle, value);
CheckAndThrow();
}
public void SetZEnable(bool value)
{
RenderDevice_SetZEnable(Handle, value);
CheckAndThrow();
}
public void SetZWriteEnable(bool value)
{
RenderDevice_SetZWriteEnable(Handle, value);
CheckAndThrow();
}
public void SetTexture(BaseTexture value)
{
RenderDevice_SetTexture(Handle, value != null ? value.Handle : IntPtr.Zero);
CheckAndThrow();
}
public void SetSamplerFilter(TextureFilter filter)
{
SetSamplerFilter(filter, filter, TextureFilter.None, 0.0f);
CheckAndThrow();
}
public void SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, TextureFilter mipfilter, float maxanisotropy)
{
RenderDevice_SetSamplerFilter(Handle, minfilter, magfilter, mipfilter, maxanisotropy);
CheckAndThrow();
}
public void SetSamplerState(TextureAddress address)
{
SetSamplerState(address, address, address);
CheckAndThrow();
}
public void SetSamplerState(TextureAddress addressU, TextureAddress addressV, TextureAddress addressW)
{
RenderDevice_SetSamplerState(Handle, addressU, addressV, addressW);
CheckAndThrow();
}
public void DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount)
{
RenderDevice_DrawIndexed(Handle, type, startIndex, primitiveCount);
CheckAndThrow();
}
public void Draw(PrimitiveType type, int startIndex, int primitiveCount)
{
RenderDevice_Draw(Handle, type, startIndex, primitiveCount);
CheckAndThrow();
}
public void Draw(PrimitiveType type, int startIndex, int primitiveCount, FlatVertex[] data)
{
RenderDevice_DrawData(Handle, type, startIndex, primitiveCount, data);
CheckAndThrow();
}
public void StartRendering(bool clear, Color4 backcolor)
{
RenderDevice_StartRendering(Handle, clear, backcolor.ToArgb(), IntPtr.Zero, true);
CheckAndThrow();
}
public void StartRendering(bool clear, Color4 backcolor, Texture target, bool usedepthbuffer)
{
RenderDevice_StartRendering(Handle, clear, backcolor.ToArgb(), target.Handle, usedepthbuffer);
CheckAndThrow();
}
public void FinishRendering()
{
RenderDevice_FinishRendering(Handle);
CheckAndThrow();
}
public void Present()
{
RenderDevice_Present(Handle);
CheckAndThrow();
}
public void ClearTexture(Color4 backcolor, Texture texture)
{
RenderDevice_ClearTexture(Handle, backcolor.ToArgb(), texture.Handle);
CheckAndThrow();
}
public void CopyTexture(CubeTexture dst, CubeMapFace face)
{
RenderDevice_CopyTexture(Handle, dst.Handle, face);
CheckAndThrow();
}
public void SetBufferData(IndexBuffer buffer, int[] data)
{
RenderDevice_SetIndexBufferData(Handle, buffer.Handle, data, data.Length * Marshal.SizeOf<int>());
CheckAndThrow();
}
public void SetBufferData(VertexBuffer buffer, int length, VertexFormat format)
{
int stride = (format == VertexFormat.Flat) ? FlatVertex.Stride : WorldVertex.Stride;
RenderDevice_SetVertexBufferData(Handle, buffer.Handle, IntPtr.Zero, length * stride, format);
CheckAndThrow();
}
public void SetBufferData(VertexBuffer buffer, FlatVertex[] data)
{
RenderDevice_SetVertexBufferData(Handle, buffer.Handle, data, data.Length * Marshal.SizeOf<FlatVertex>(), VertexFormat.Flat);
CheckAndThrow();
}
public void SetBufferData(VertexBuffer buffer, WorldVertex[] data)
{
RenderDevice_SetVertexBufferData(Handle, buffer.Handle, data, data.Length * Marshal.SizeOf<WorldVertex>(), VertexFormat.World);
CheckAndThrow();
}
public void SetBufferSubdata(VertexBuffer buffer, long destOffset, FlatVertex[] data)
{
RenderDevice_SetVertexBufferSubdata(Handle, buffer.Handle, destOffset * FlatVertex.Stride, data, data.Length * FlatVertex.Stride);
CheckAndThrow();
}
public void SetBufferSubdata(VertexBuffer buffer, long destOffset, WorldVertex[] data)
{
RenderDevice_SetVertexBufferSubdata(Handle, buffer.Handle, destOffset * WorldVertex.Stride, data, data.Length * WorldVertex.Stride);
CheckAndThrow();
}
public void SetBufferSubdata(VertexBuffer buffer, FlatVertex[] data, long size)
{
if (size < 0 || size > data.Length) throw new ArgumentOutOfRangeException("size");
RenderDevice_SetVertexBufferSubdata(Handle, buffer.Handle, 0, data, size * FlatVertex.Stride);
CheckAndThrow();
}
public void SetPixels(Texture texture, System.Drawing.Bitmap bitmap)
@ -290,6 +343,7 @@ namespace CodeImp.DoomBuilder.Rendering
RenderDevice_SetPixels(Handle, texture.Handle, bmpdata.Scan0);
bitmap.UnlockBits(bmpdata);
CheckAndThrow();
}
public void SetPixels(CubeTexture texture, CubeMapFace face, System.Drawing.Bitmap bitmap)
@ -302,6 +356,7 @@ namespace CodeImp.DoomBuilder.Rendering
RenderDevice_SetCubePixels(Handle, texture.Handle, face, bmpdata.Scan0);
bitmap.UnlockBits(bmpdata);
CheckAndThrow();
}
internal void RegisterResource(IRenderResource res)
@ -350,10 +405,13 @@ namespace CodeImp.DoomBuilder.Rendering
static extern void RenderDevice_Delete(IntPtr handle);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr RenderDevice_SetShader(IntPtr hwnd, ShaderName name);
static extern IntPtr RenderDevice_GetError(IntPtr handle);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr RenderDevice_SetUniform(IntPtr hwnd, UniformName name, float[] data, int count);
static extern IntPtr RenderDevice_SetShader(IntPtr handle, ShaderName name);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr RenderDevice_SetUniform(IntPtr handle, UniformName name, float[] data, int count);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
static extern void RenderDevice_SetVertexBuffer(IntPtr handle, IntPtr buffer);

View file

@ -6,10 +6,13 @@
#include "Texture.h"
#include "ShaderManager.h"
#include <stdexcept>
#include <cstdarg>
RenderDevice::RenderDevice(void* disp, void* window)
{
memset(mUniforms, 0, sizeof(mUniforms));
memset(mLastError, 0, sizeof(mLastError));
memset(mReturnError, 0, sizeof(mReturnError));
Context = IOpenGLContext::Create(disp, window);
if (Context)
@ -25,7 +28,7 @@ RenderDevice::RenderDevice(void* disp, void* window)
mShaderManager = std::make_unique<ShaderManager>();
CheckError();
CheckGLError();
Context->ClearCurrent();
}
}
@ -270,7 +273,16 @@ void RenderDevice::StartRendering(bool clear, int backcolor, Texture* target, bo
if (target)
{
glBindFramebuffer(GL_FRAMEBUFFER, target->GetFramebuffer(usedepthbuffer));
GLuint framebuffer = 0;
try
{
framebuffer = target->GetFramebuffer(usedepthbuffer);
}
catch (std::runtime_error& e)
{
SetError("Error setting render target: %s", e.what());
}
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
mViewportWidth = target->GetWidth();
mViewportHeight = target->GetHeight();
ApplyViewport();
@ -310,7 +322,7 @@ void RenderDevice::StartRendering(bool clear, int backcolor, Texture* target, bo
void RenderDevice::FinishRendering()
{
CheckError();
CheckGLError();
Context->ClearCurrent();
mContextIsCurrent = false;
}
@ -408,11 +420,27 @@ void RenderDevice::InvalidateTexture(Texture* texture)
}
}
void RenderDevice::CheckError()
void RenderDevice::CheckGLError()
{
GLenum error = glGetError();
if (error != GL_NO_ERROR)
throw std::runtime_error("OpenGL error!");
SetError("OpenGL error: %d", error);
}
void RenderDevice::SetError(const char* fmt, ...)
{
va_list va;
va_start(va, fmt);
mLastError[sizeof(mLastError) - 1] = 0;
_vsnprintf(mLastError, sizeof(mLastError)-1, fmt, va);
va_end(va);
}
const char* RenderDevice::GetError()
{
memcpy(mReturnError, mLastError, sizeof(mReturnError));
mLastError[0] = 0;
return mReturnError;
}
Shader* RenderDevice::GetActiveShader()
@ -492,7 +520,14 @@ void RenderDevice::ApplyChanges()
void RenderDevice::ApplyShader()
{
GetActiveShader()->Bind();
Shader* curShader = GetActiveShader();
if (!curShader->CheckCompile())
{
SetError("Failed to bind shader:\r\n%s", curShader->GetCompileError().c_str());
return;
}
curShader->Bind();
mShaderChanged = false;
}
@ -652,6 +687,11 @@ void RenderDevice_Delete(RenderDevice* device)
delete device;
}
const char* RenderDevice_GetError(RenderDevice* device)
{
return device->GetError();
}
void RenderDevice_SetShader(RenderDevice* device, ShaderName name)
{
device->SetShader(name);

View file

@ -126,7 +126,9 @@ public:
void ApplyBlendState();
void ApplyDepthState();
void CheckError();
void CheckGLError();
void SetError(const char* fmt, ...);
const char* GetError();
Shader* GetActiveShader();
@ -186,6 +188,9 @@ public:
bool mContextIsCurrent = false;
char mLastError[4096];
char mReturnError[4096];
int mViewportWidth = 0;
int mViewportHeight = 0;
};

View file

@ -4,31 +4,54 @@
#include "RenderDevice.h"
#include <stdexcept>
void Shader::Setup(const std::string& vertexShader, const std::string& fragmentShader, bool alphatest)
void Shader::Setup(const std::string& identifier, const std::string& vertexShader, const std::string& fragmentShader, bool alphatest)
{
mIdentifier = identifier;
mVertexText = vertexShader;
mFragmentText = fragmentShader;
mAlphatest = alphatest;
}
void Shader::Bind()
bool Shader::CheckCompile()
{
bool firstCall = !mProgramBuilt;
if (firstCall)
{
mProgramBuilt = true;
CreateProgram();
glUseProgram(mProgram);
glUniform1i(glGetUniformLocation(mProgram, "texture1"), 0);
glUseProgram(0);
}
if (!mProgram)
return !mErrors.size();
}
std::string Shader::GetCompileError()
{
std::string lines = "Error compiling ";
if (!mVertexShader)
lines += "vertex ";
else if (!mFragmentShader)
lines += "fragment ";
lines += "shader \"" + mIdentifier + "\":\r\n";
for (auto c : mErrors)
{
if (c == '\r')
continue;
if (c == '\n')
lines += "\r\n";
else lines += c;
}
return lines;
}
void Shader::Bind()
{
if (!mProgram || !mProgramBuilt || mErrors.size())
return;
glUseProgram(mProgram);
if (firstCall)
{
glUniform1i(glGetUniformLocation(mProgram, "texture1"), 0);
}
}
void Shader::CreateProgram()

View file

@ -11,15 +11,20 @@ public:
Shader() = default;
void ReleaseResources();
void Setup(const std::string& vertexShader, const std::string& fragmentShader, bool alphatest);
void Setup(const std::string& identifier, const std::string& vertexShader, const std::string& fragmentShader, bool alphatest);
bool CheckCompile();
void Bind();
std::string GetIdentifier();
std::string GetCompileError();
GLuint UniformLocations[(int)UniformName::NumUniforms] = { 0 };
private:
void CreateProgram();
GLuint CompileShader(const std::string& code, GLenum type);
std::string mIdentifier;
std::string mVertexText;
std::string mFragmentText;
bool mAlphatest = false;

View file

@ -37,14 +37,42 @@ static const ShaderPair ShaderSources[(int)ShaderName::count] = {
{ world3D_vs_lightpass, world3D_ps_lightpass }
};
static const std::string ShaderNames[(int)ShaderName::count] = {
"display2d_fsaa",
"display2d_normal",
"display2d_fullbright",
"things2d_thing",
"things2d_sprite",
"things2d_fill",
"plotter",
"world3d_main",
"world3d_fullbright",
"world3d_main_highlight",
"world3d_fullbright_highlight",
"world3d_main_vertexcolor",
"world3d_skybox",
"world3d_main_highlight_vertexcolor",
"world3d_p7",
"world3d_main_fog",
"world3d_p9",
"world3d_main_highlight_fog",
"world3d_p11",
"world3d_main_fog_vertexcolor",
"world3d_p13",
"world3d_main_highlight_fog_vertexcolor",
"world3d_vertex_color",
"world3d_constant_color",
"world3d_lightpass",
};
ShaderManager::ShaderManager()
{
for (int i = 0; i < (int)ShaderName::count; i++)
{
if (ShaderSources[i].vs && ShaderSources[i].ps)
{
Shaders[i].Setup(ShaderSources[i].vs, ShaderSources[i].ps, false);
AlphaTestShaders[i].Setup(ShaderSources[i].vs, ShaderSources[i].ps, true);
Shaders[i].Setup(ShaderNames[i], ShaderSources[i].vs, ShaderSources[i].ps, false);
AlphaTestShaders[i].Setup(ShaderNames[i], ShaderSources[i].vs, ShaderSources[i].ps, true);
}
}
}

View file

@ -3,6 +3,7 @@ EXPORTS
RenderDevice_New
RenderDevice_Delete
RenderDevice_GetError
RenderDevice_SetShader
RenderDevice_SetUniform
RenderDevice_SetVertexBuffer