mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
Merge branch 'master' into asmjit
This commit is contained in:
commit
ce46f5165a
18 changed files with 482 additions and 86 deletions
|
@ -37,10 +37,11 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
#define MAX_ERRORTEXT 1024
|
#define MAX_ERRORTEXT 1024
|
||||||
|
|
||||||
class CDoomError
|
class CDoomError : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDoomError ()
|
CDoomError ()
|
||||||
|
@ -69,13 +70,22 @@ public:
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
char const *what() const override
|
||||||
|
{
|
||||||
|
return m_Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char m_Message[MAX_ERRORTEXT];
|
char m_Message[MAX_ERRORTEXT];
|
||||||
};
|
};
|
||||||
|
|
||||||
class CNoRunExit : public CDoomError
|
class CNoRunExit : public std::exception
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
CNoRunExit() : std::exception("NoRunExit")
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CRecoverableError : public CDoomError
|
class CRecoverableError : public CDoomError
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "doomerrors.h"
|
#include "doomerrors.h"
|
||||||
#include "cmdlib.h"
|
#include "cmdlib.h"
|
||||||
|
#include "md5.h"
|
||||||
|
#include "m_misc.h"
|
||||||
#include "hwrenderer/utility/hw_shaderpatcher.h"
|
#include "hwrenderer/utility/hw_shaderpatcher.h"
|
||||||
#include "hwrenderer/data/shaderuniforms.h"
|
#include "hwrenderer/data/shaderuniforms.h"
|
||||||
#include "hwrenderer/scene/hw_viewpointuniforms.h"
|
#include "hwrenderer/scene/hw_viewpointuniforms.h"
|
||||||
|
@ -42,10 +44,166 @@
|
||||||
#include "r_data/matrix.h"
|
#include "r_data/matrix.h"
|
||||||
#include "gl/renderer/gl_renderer.h"
|
#include "gl/renderer/gl_renderer.h"
|
||||||
#include "gl/shaders/gl_shader.h"
|
#include "gl/shaders/gl_shader.h"
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace OpenGLRenderer
|
namespace OpenGLRenderer
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct ProgramBinary
|
||||||
|
{
|
||||||
|
uint32_t format;
|
||||||
|
TArray<uint8_t> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *ShaderMagic = "ZDSC";
|
||||||
|
|
||||||
|
static std::map<FString, std::unique_ptr<ProgramBinary>> ShaderCache; // Not a TMap because it doesn't support unique_ptr move semantics
|
||||||
|
|
||||||
|
bool IsShaderCacheActive()
|
||||||
|
{
|
||||||
|
static bool active = true;
|
||||||
|
static bool firstcall = true;
|
||||||
|
|
||||||
|
if (firstcall)
|
||||||
|
{
|
||||||
|
const char *vendor = (const char *)glGetString(GL_VENDOR);
|
||||||
|
active = !(strstr(vendor, "Intel") == nullptr);
|
||||||
|
firstcall = false;
|
||||||
|
}
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FString CalcProgramBinaryChecksum(const FString &vertex, const FString &fragment)
|
||||||
|
{
|
||||||
|
const GLubyte *vendor = glGetString(GL_VENDOR);
|
||||||
|
const GLubyte *renderer = glGetString(GL_RENDERER);
|
||||||
|
const GLubyte *version = glGetString(GL_VERSION);
|
||||||
|
|
||||||
|
uint8_t digest[16];
|
||||||
|
MD5Context md5;
|
||||||
|
md5.Update(vendor, (unsigned int)strlen((const char*)vendor));
|
||||||
|
md5.Update(renderer, (unsigned int)strlen((const char*)renderer));
|
||||||
|
md5.Update(version, (unsigned int)strlen((const char*)version));
|
||||||
|
md5.Update((const uint8_t *)vertex.GetChars(), (unsigned int)vertex.Len());
|
||||||
|
md5.Update((const uint8_t *)fragment.GetChars(), (unsigned int)fragment.Len());
|
||||||
|
md5.Final(digest);
|
||||||
|
|
||||||
|
char hexdigest[33];
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
int v = digest[i] >> 4;
|
||||||
|
hexdigest[i * 2] = v < 10 ? ('0' + v) : ('a' + v - 10);
|
||||||
|
v = digest[i] & 15;
|
||||||
|
hexdigest[i * 2 + 1] = v < 10 ? ('0' + v) : ('a' + v - 10);
|
||||||
|
}
|
||||||
|
hexdigest[32] = 0;
|
||||||
|
return hexdigest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FString CreateProgramCacheName(bool create)
|
||||||
|
{
|
||||||
|
FString path = M_GetCachePath(create);
|
||||||
|
if (create) CreatePath(path);
|
||||||
|
path << "/shadercache.zdsc";
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LoadShaders()
|
||||||
|
{
|
||||||
|
static bool loaded = false;
|
||||||
|
if (loaded)
|
||||||
|
return;
|
||||||
|
loaded = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FString path = CreateProgramCacheName(false);
|
||||||
|
FileReader fr;
|
||||||
|
if (!fr.OpenFile(path))
|
||||||
|
throw std::runtime_error("Could not open shader file");
|
||||||
|
|
||||||
|
char magic[4];
|
||||||
|
fr.Read(magic, 4);
|
||||||
|
if (memcmp(magic, ShaderMagic, 4) != 0)
|
||||||
|
throw std::runtime_error("Not a shader cache file");
|
||||||
|
|
||||||
|
uint32_t count = fr.ReadUInt32();
|
||||||
|
if (count > 512)
|
||||||
|
throw std::runtime_error("Too many shaders cached");
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
char hexdigest[33];
|
||||||
|
if (fr.Read(hexdigest, 32) != 32)
|
||||||
|
throw std::runtime_error("Read error");
|
||||||
|
hexdigest[32] = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<ProgramBinary> binary(new ProgramBinary());
|
||||||
|
binary->format = fr.ReadUInt32();
|
||||||
|
uint32_t size = fr.ReadUInt32();
|
||||||
|
if (size > 1024 * 1024)
|
||||||
|
throw std::runtime_error("Shader too big, probably file corruption");
|
||||||
|
|
||||||
|
binary->data.Resize(size);
|
||||||
|
if (fr.Read(binary->data.Data(), binary->data.Size()) != binary->data.Size())
|
||||||
|
throw std::runtime_error("Read error");
|
||||||
|
|
||||||
|
ShaderCache[hexdigest] = std::move(binary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
ShaderCache.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SaveShaders()
|
||||||
|
{
|
||||||
|
FString path = CreateProgramCacheName(true);
|
||||||
|
std::unique_ptr<FileWriter> fw(FileWriter::Open(path));
|
||||||
|
if (fw)
|
||||||
|
{
|
||||||
|
uint32_t count = (uint32_t)ShaderCache.size();
|
||||||
|
fw->Write(ShaderMagic, 4);
|
||||||
|
fw->Write(&count, sizeof(uint32_t));
|
||||||
|
for (const auto &it : ShaderCache)
|
||||||
|
{
|
||||||
|
uint32_t size = it.second->data.Size();
|
||||||
|
fw->Write(it.first.GetChars(), 32);
|
||||||
|
fw->Write(&it.second->format, sizeof(uint32_t));
|
||||||
|
fw->Write(&size, sizeof(uint32_t));
|
||||||
|
fw->Write(it.second->data.Data(), it.second->data.Size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<uint8_t> LoadCachedProgramBinary(const FString &vertex, const FString &fragment, uint32_t &binaryFormat)
|
||||||
|
{
|
||||||
|
LoadShaders();
|
||||||
|
|
||||||
|
auto it = ShaderCache.find(CalcProgramBinaryChecksum(vertex, fragment));
|
||||||
|
if (it != ShaderCache.end())
|
||||||
|
{
|
||||||
|
binaryFormat = it->second->format;
|
||||||
|
return it->second->data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
binaryFormat = 0;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveCachedProgramBinary(const FString &vertex, const FString &fragment, const TArray<uint8_t> &binary, uint32_t binaryFormat)
|
||||||
|
{
|
||||||
|
auto &entry = ShaderCache[CalcProgramBinaryChecksum(vertex, fragment)];
|
||||||
|
entry.reset(new ProgramBinary());
|
||||||
|
entry->format = binaryFormat;
|
||||||
|
entry->data = binary;
|
||||||
|
|
||||||
|
SaveShaders();
|
||||||
|
}
|
||||||
|
|
||||||
bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * light_fragprog, const char * defines)
|
bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * light_fragprog, const char * defines)
|
||||||
{
|
{
|
||||||
|
@ -273,56 +431,87 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
||||||
vp_comb.Substitute("gl_ClipDistance", "//");
|
vp_comb.Substitute("gl_ClipDistance", "//");
|
||||||
}
|
}
|
||||||
|
|
||||||
hVertProg = glCreateShader(GL_VERTEX_SHADER);
|
|
||||||
hFragProg = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
|
|
||||||
FGLDebug::LabelObject(GL_SHADER, hVertProg, vert_prog_lump);
|
|
||||||
FGLDebug::LabelObject(GL_SHADER, hFragProg, frag_prog_lump);
|
|
||||||
|
|
||||||
int vp_size = (int)vp_comb.Len();
|
|
||||||
int fp_size = (int)fp_comb.Len();
|
|
||||||
|
|
||||||
const char *vp_ptr = vp_comb.GetChars();
|
|
||||||
const char *fp_ptr = fp_comb.GetChars();
|
|
||||||
|
|
||||||
glShaderSource(hVertProg, 1, &vp_ptr, &vp_size);
|
|
||||||
glShaderSource(hFragProg, 1, &fp_ptr, &fp_size);
|
|
||||||
|
|
||||||
glCompileShader(hVertProg);
|
|
||||||
glCompileShader(hFragProg);
|
|
||||||
|
|
||||||
hShader = glCreateProgram();
|
hShader = glCreateProgram();
|
||||||
FGLDebug::LabelObject(GL_PROGRAM, hShader, name);
|
FGLDebug::LabelObject(GL_PROGRAM, hShader, name);
|
||||||
|
|
||||||
glAttachShader(hShader, hVertProg);
|
uint32_t binaryFormat = 0;
|
||||||
glAttachShader(hShader, hFragProg);
|
TArray<uint8_t> binary;
|
||||||
|
if (IsShaderCacheActive())
|
||||||
|
binary = LoadCachedProgramBinary(vp_comb, fp_comb, binaryFormat);
|
||||||
|
|
||||||
glLinkProgram(hShader);
|
bool linked = false;
|
||||||
|
if (binary.Size() > 0 && glProgramBinary)
|
||||||
glGetShaderInfoLog(hVertProg, 10000, NULL, buffer);
|
|
||||||
if (*buffer)
|
|
||||||
{
|
{
|
||||||
error << "Vertex shader:\n" << buffer << "\n";
|
glProgramBinary(hShader, binaryFormat, binary.Data(), binary.Size());
|
||||||
}
|
GLint status = 0;
|
||||||
glGetShaderInfoLog(hFragProg, 10000, NULL, buffer);
|
glGetProgramiv(hShader, GL_LINK_STATUS, &status);
|
||||||
if (*buffer)
|
linked = (status == GL_TRUE);
|
||||||
{
|
|
||||||
error << "Fragment shader:\n" << buffer << "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glGetProgramInfoLog(hShader, 10000, NULL, buffer);
|
if (!linked)
|
||||||
if (*buffer)
|
|
||||||
{
|
{
|
||||||
error << "Linking:\n" << buffer << "\n";
|
hVertProg = glCreateShader(GL_VERTEX_SHADER);
|
||||||
}
|
hFragProg = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
int linked;
|
|
||||||
glGetProgramiv(hShader, GL_LINK_STATUS, &linked);
|
|
||||||
if (linked == 0)
|
|
||||||
{
|
|
||||||
// only print message if there's an error.
|
|
||||||
I_Error("Init Shader '%s':\n%s\n", name, error.GetChars());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
FGLDebug::LabelObject(GL_SHADER, hVertProg, vert_prog_lump);
|
||||||
|
FGLDebug::LabelObject(GL_SHADER, hFragProg, frag_prog_lump);
|
||||||
|
|
||||||
|
int vp_size = (int)vp_comb.Len();
|
||||||
|
int fp_size = (int)fp_comb.Len();
|
||||||
|
|
||||||
|
const char *vp_ptr = vp_comb.GetChars();
|
||||||
|
const char *fp_ptr = fp_comb.GetChars();
|
||||||
|
|
||||||
|
glShaderSource(hVertProg, 1, &vp_ptr, &vp_size);
|
||||||
|
glShaderSource(hFragProg, 1, &fp_ptr, &fp_size);
|
||||||
|
|
||||||
|
glCompileShader(hVertProg);
|
||||||
|
glCompileShader(hFragProg);
|
||||||
|
|
||||||
|
glAttachShader(hShader, hVertProg);
|
||||||
|
glAttachShader(hShader, hFragProg);
|
||||||
|
|
||||||
|
glLinkProgram(hShader);
|
||||||
|
|
||||||
|
glGetShaderInfoLog(hVertProg, 10000, NULL, buffer);
|
||||||
|
if (*buffer)
|
||||||
|
{
|
||||||
|
error << "Vertex shader:\n" << buffer << "\n";
|
||||||
|
}
|
||||||
|
glGetShaderInfoLog(hFragProg, 10000, NULL, buffer);
|
||||||
|
if (*buffer)
|
||||||
|
{
|
||||||
|
error << "Fragment shader:\n" << buffer << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
glGetProgramInfoLog(hShader, 10000, NULL, buffer);
|
||||||
|
if (*buffer)
|
||||||
|
{
|
||||||
|
error << "Linking:\n" << buffer << "\n";
|
||||||
|
}
|
||||||
|
GLint status = 0;
|
||||||
|
glGetProgramiv(hShader, GL_LINK_STATUS, &status);
|
||||||
|
linked = (status == GL_TRUE);
|
||||||
|
if (!linked)
|
||||||
|
{
|
||||||
|
// only print message if there's an error.
|
||||||
|
I_Error("Init Shader '%s':\n%s\n", name, error.GetChars());
|
||||||
|
}
|
||||||
|
else if (glProgramBinary && IsShaderCacheActive())
|
||||||
|
{
|
||||||
|
int binaryLength = 0;
|
||||||
|
glGetProgramiv(hShader, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||||
|
binary.Resize(binaryLength);
|
||||||
|
glGetProgramBinary(hShader, binary.Size(), &binaryLength, &binaryFormat, binary.Data());
|
||||||
|
binary.Resize(binaryLength);
|
||||||
|
SaveCachedProgramBinary(vp_comb, fp_comb, binary, binaryFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hVertProg = 0;
|
||||||
|
hFragProg = 0;
|
||||||
|
}
|
||||||
|
|
||||||
muDesaturation.Init(hShader, "uDesaturationFactor");
|
muDesaturation.Init(hShader, "uDesaturationFactor");
|
||||||
muFogEnabled.Init(hShader, "uFogEnabled");
|
muFogEnabled.Init(hShader, "uFogEnabled");
|
||||||
|
@ -376,7 +565,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
||||||
if (shadowmapindex > 0) glUniform1i(shadowmapindex, 16);
|
if (shadowmapindex > 0) glUniform1i(shadowmapindex, 16);
|
||||||
|
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
return !!linked;
|
return linked;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -388,8 +577,10 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
||||||
FShader::~FShader()
|
FShader::~FShader()
|
||||||
{
|
{
|
||||||
glDeleteProgram(hShader);
|
glDeleteProgram(hShader);
|
||||||
glDeleteShader(hVertProg);
|
if (hVertProg != 0)
|
||||||
glDeleteShader(hFragProg);
|
glDeleteShader(hVertProg);
|
||||||
|
if (hFragProg != 0)
|
||||||
|
glDeleteShader(hFragProg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,10 @@
|
||||||
namespace OpenGLRenderer
|
namespace OpenGLRenderer
|
||||||
{
|
{
|
||||||
|
|
||||||
|
bool IsShaderCacheActive();
|
||||||
|
TArray<uint8_t> LoadCachedProgramBinary(const FString &vertex, const FString &fragment, uint32_t &binaryFormat);
|
||||||
|
void SaveCachedProgramBinary(const FString &vertex, const FString &fragment, const TArray<uint8_t> &binary, uint32_t binaryFormat);
|
||||||
|
|
||||||
FShaderProgram::FShaderProgram()
|
FShaderProgram::FShaderProgram()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumShaderTypes; i++)
|
for (int i = 0; i < NumShaderTypes; i++)
|
||||||
|
@ -94,14 +98,20 @@ void FShaderProgram::Compile(ShaderType type, const char *lumpName, const char *
|
||||||
}
|
}
|
||||||
|
|
||||||
void FShaderProgram::Compile(ShaderType type, const char *name, const FString &code, const char *defines, int maxGlslVersion)
|
void FShaderProgram::Compile(ShaderType type, const char *name, const FString &code, const char *defines, int maxGlslVersion)
|
||||||
|
{
|
||||||
|
mShaderNames[type] = name;
|
||||||
|
mShaderSources[type] = PatchShader(type, code, defines, maxGlslVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FShaderProgram::CompileShader(ShaderType type)
|
||||||
{
|
{
|
||||||
CreateShader(type);
|
CreateShader(type);
|
||||||
|
|
||||||
const auto &handle = mShaders[type];
|
const auto &handle = mShaders[type];
|
||||||
|
|
||||||
FGLDebug::LabelObject(GL_SHADER, handle, name);
|
FGLDebug::LabelObject(GL_SHADER, handle, mShaderNames[type]);
|
||||||
|
|
||||||
FString patchedCode = PatchShader(type, code, defines, maxGlslVersion);
|
const FString &patchedCode = mShaderSources[type];
|
||||||
int lengths[1] = { (int)patchedCode.Len() };
|
int lengths[1] = { (int)patchedCode.Len() };
|
||||||
const char *sources[1] = { patchedCode.GetChars() };
|
const char *sources[1] = { patchedCode.GetChars() };
|
||||||
glShaderSource(handle, 1, sources, lengths);
|
glShaderSource(handle, 1, sources, lengths);
|
||||||
|
@ -112,7 +122,7 @@ void FShaderProgram::Compile(ShaderType type, const char *name, const FString &c
|
||||||
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||||
if (status == GL_FALSE)
|
if (status == GL_FALSE)
|
||||||
{
|
{
|
||||||
I_FatalError("Compile Shader '%s':\n%s\n", name, GetShaderInfoLog(handle).GetChars());
|
I_FatalError("Compile Shader '%s':\n%s\n", mShaderNames[type].GetChars(), GetShaderInfoLog(handle).GetChars());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -131,13 +141,45 @@ void FShaderProgram::Compile(ShaderType type, const char *name, const FString &c
|
||||||
void FShaderProgram::Link(const char *name)
|
void FShaderProgram::Link(const char *name)
|
||||||
{
|
{
|
||||||
FGLDebug::LabelObject(GL_PROGRAM, mProgram, name);
|
FGLDebug::LabelObject(GL_PROGRAM, mProgram, name);
|
||||||
glLinkProgram(mProgram);
|
|
||||||
|
|
||||||
GLint status = 0;
|
uint32_t binaryFormat = 0;
|
||||||
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
|
TArray<uint8_t> binary;
|
||||||
if (status == GL_FALSE)
|
if (IsShaderCacheActive())
|
||||||
|
binary = LoadCachedProgramBinary(mShaderSources[Vertex], mShaderSources[Fragment], binaryFormat);
|
||||||
|
|
||||||
|
bool loadedFromBinary = false;
|
||||||
|
if (binary.Size() > 0 && glProgramBinary)
|
||||||
{
|
{
|
||||||
I_FatalError("Link Shader '%s':\n%s\n", name, GetProgramInfoLog(mProgram).GetChars());
|
if (mProgram == 0)
|
||||||
|
mProgram = glCreateProgram();
|
||||||
|
glProgramBinary(mProgram, binaryFormat, binary.Data(), binary.Size());
|
||||||
|
GLint status = 0;
|
||||||
|
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
|
||||||
|
loadedFromBinary = (status == GL_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loadedFromBinary)
|
||||||
|
{
|
||||||
|
CompileShader(Vertex);
|
||||||
|
CompileShader(Fragment);
|
||||||
|
|
||||||
|
glLinkProgram(mProgram);
|
||||||
|
|
||||||
|
GLint status = 0;
|
||||||
|
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
|
||||||
|
if (status == GL_FALSE)
|
||||||
|
{
|
||||||
|
I_FatalError("Link Shader '%s':\n%s\n", name, GetProgramInfoLog(mProgram).GetChars());
|
||||||
|
}
|
||||||
|
else if (glProgramBinary && IsShaderCacheActive())
|
||||||
|
{
|
||||||
|
int binaryLength = 0;
|
||||||
|
glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||||
|
binary.Resize(binaryLength);
|
||||||
|
glGetProgramBinary(mProgram, binary.Size(), &binaryLength, &binaryFormat, binary.Data());
|
||||||
|
binary.Resize(binaryLength);
|
||||||
|
SaveCachedProgramBinary(mShaderSources[Vertex], mShaderSources[Fragment], binary, binaryFormat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is only for old OpenGL which didn't allow to set the binding from within the shader.
|
// This is only for old OpenGL which didn't allow to set the binding from within the shader.
|
||||||
|
|
|
@ -30,6 +30,7 @@ private:
|
||||||
FShaderProgram(const FShaderProgram &) = delete;
|
FShaderProgram(const FShaderProgram &) = delete;
|
||||||
FShaderProgram &operator=(const FShaderProgram &) = delete;
|
FShaderProgram &operator=(const FShaderProgram &) = delete;
|
||||||
|
|
||||||
|
void CompileShader(ShaderType type);
|
||||||
FString PatchShader(ShaderType type, const FString &code, const char *defines, int maxGlslVersion);
|
FString PatchShader(ShaderType type, const FString &code, const char *defines, int maxGlslVersion);
|
||||||
|
|
||||||
void CreateShader(ShaderType type);
|
void CreateShader(ShaderType type);
|
||||||
|
@ -38,6 +39,8 @@ private:
|
||||||
|
|
||||||
GLuint mProgram = 0;
|
GLuint mProgram = 0;
|
||||||
GLuint mShaders[NumShaderTypes];
|
GLuint mShaders[NumShaderTypes];
|
||||||
|
FString mShaderSources[NumShaderTypes];
|
||||||
|
FString mShaderNames[NumShaderTypes];
|
||||||
TArray<std::pair<FString, int>> samplerstobind;
|
TArray<std::pair<FString, int>> samplerstobind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,8 @@ FModelVertexBuffer::FModelVertexBuffer(bool needindex, bool singleframe)
|
||||||
{ 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FModelVertex, x) },
|
{ 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FModelVertex, x) },
|
||||||
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FModelVertex, u) },
|
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FModelVertex, u) },
|
||||||
{ 0, VATTR_NORMAL, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) },
|
{ 0, VATTR_NORMAL, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) },
|
||||||
{ 1, VATTR_VERTEX2, VFmt_Float3, (int)myoffsetof(FModelVertex, x) }
|
{ 1, VATTR_VERTEX2, VFmt_Float3, (int)myoffsetof(FModelVertex, x) },
|
||||||
|
{ 1, VATTR_NORMAL2, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) }
|
||||||
};
|
};
|
||||||
mVertexBuffer->SetFormat(2, 4, sizeof(FModelVertex), format);
|
mVertexBuffer->SetFormat(2, 4, sizeof(FModelVertex), format);
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,8 +127,13 @@ void PolyTriangleThreadData::ClearStencil(uint8_t value)
|
||||||
int height = buffer->Height();
|
int height = buffer->Height();
|
||||||
uint8_t *data = buffer->Values();
|
uint8_t *data = buffer->Values();
|
||||||
|
|
||||||
data += core * width;
|
int start_y = numa_node * height / num_numa_nodes;
|
||||||
for (int y = core; y < height; y += num_cores)
|
int end_y = (numa_node + 1) * height / num_numa_nodes;
|
||||||
|
int core_skip = (num_cores - (start_y - core) % num_cores) % num_cores;
|
||||||
|
start_y += core_skip;
|
||||||
|
|
||||||
|
data += start_y * width;
|
||||||
|
for (int y = start_y; y < end_y; y += num_cores)
|
||||||
{
|
{
|
||||||
memset(data, value, width);
|
memset(data, value, width);
|
||||||
data += num_cores * width;
|
data += num_cores * width;
|
||||||
|
@ -146,6 +151,8 @@ void PolyTriangleThreadData::SetViewport(int x, int y, int width, int height, ui
|
||||||
dest_height = new_dest_height;
|
dest_height = new_dest_height;
|
||||||
dest_pitch = new_dest_pitch;
|
dest_pitch = new_dest_pitch;
|
||||||
dest_bgra = new_dest_bgra;
|
dest_bgra = new_dest_bgra;
|
||||||
|
numa_start_y = numa_node * dest_height / num_numa_nodes;
|
||||||
|
numa_end_y = (numa_node + 1) * dest_height / num_numa_nodes;
|
||||||
ccw = true;
|
ccw = true;
|
||||||
weaponScene = false;
|
weaponScene = false;
|
||||||
}
|
}
|
||||||
|
@ -642,7 +649,7 @@ int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVert
|
||||||
PolyTriangleThreadData *PolyTriangleThreadData::Get(DrawerThread *thread)
|
PolyTriangleThreadData *PolyTriangleThreadData::Get(DrawerThread *thread)
|
||||||
{
|
{
|
||||||
if (!thread->poly)
|
if (!thread->poly)
|
||||||
thread->poly = std::make_shared<PolyTriangleThreadData>(thread->core, thread->num_cores);
|
thread->poly = std::make_shared<PolyTriangleThreadData>(thread->core, thread->num_cores, thread->numa_node, thread->num_numa_nodes);
|
||||||
return thread->poly.get();
|
return thread->poly.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
class PolyTriangleThreadData
|
class PolyTriangleThreadData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PolyTriangleThreadData(int32_t core, int32_t num_cores) : core(core), num_cores(num_cores) { }
|
PolyTriangleThreadData(int32_t core, int32_t num_cores, int32_t numa_node, int32_t num_numa_nodes) : core(core), num_cores(num_cores), numa_node(numa_node), num_numa_nodes(num_numa_nodes) { }
|
||||||
|
|
||||||
void ClearStencil(uint8_t value);
|
void ClearStencil(uint8_t value);
|
||||||
void SetViewport(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra);
|
void SetViewport(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra);
|
||||||
|
@ -63,12 +63,18 @@ public:
|
||||||
|
|
||||||
int32_t core;
|
int32_t core;
|
||||||
int32_t num_cores;
|
int32_t num_cores;
|
||||||
|
int32_t numa_node;
|
||||||
|
int32_t num_numa_nodes;
|
||||||
|
|
||||||
|
int numa_start_y;
|
||||||
|
int numa_end_y;
|
||||||
|
|
||||||
// The number of lines to skip to reach the first line to be rendered by this thread
|
// The number of lines to skip to reach the first line to be rendered by this thread
|
||||||
int skipped_by_thread(int first_line)
|
int skipped_by_thread(int first_line)
|
||||||
{
|
{
|
||||||
int core_skip = (num_cores - (first_line - core) % num_cores) % num_cores;
|
int clip_first_line = MAX(first_line, numa_start_y);
|
||||||
return core_skip;
|
int core_skip = (num_cores - (clip_first_line - core) % num_cores) % num_cores;
|
||||||
|
return clip_first_line + core_skip - first_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PolyTriangleThreadData *Get(DrawerThread *thread);
|
static PolyTriangleThreadData *Get(DrawerThread *thread);
|
||||||
|
|
|
@ -59,9 +59,9 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
|
||||||
SortVertices(args, sortedVertices);
|
SortVertices(args, sortedVertices);
|
||||||
|
|
||||||
int clipright = args->clipright;
|
int clipright = args->clipright;
|
||||||
int clipbottom = args->clipbottom;
|
int cliptop = thread->numa_start_y;
|
||||||
|
int clipbottom = MIN(args->clipbottom, thread->numa_end_y);
|
||||||
|
|
||||||
// Ranges that different triangles edges are active
|
|
||||||
int topY = (int)(sortedVertices[0]->y + 0.5f);
|
int topY = (int)(sortedVertices[0]->y + 0.5f);
|
||||||
int midY = (int)(sortedVertices[1]->y + 0.5f);
|
int midY = (int)(sortedVertices[1]->y + 0.5f);
|
||||||
int bottomY = (int)(sortedVertices[2]->y + 0.5f);
|
int bottomY = (int)(sortedVertices[2]->y + 0.5f);
|
||||||
|
@ -1567,6 +1567,7 @@ void DrawRect8(const void *destOrg, int destWidth, int destHeight, int destPitch
|
||||||
uint32_t stepV = (int32_t)(fstepV * 0x1000000);
|
uint32_t stepV = (int32_t)(fstepV * 0x1000000);
|
||||||
|
|
||||||
uint32_t posV = startV;
|
uint32_t posV = startV;
|
||||||
|
y1 = MIN(y1, thread->numa_end_y);
|
||||||
int num_cores = thread->num_cores;
|
int num_cores = thread->num_cores;
|
||||||
int skip = thread->skipped_by_thread(y0);
|
int skip = thread->skipped_by_thread(y0);
|
||||||
posV += skip * stepV;
|
posV += skip * stepV;
|
||||||
|
@ -1817,6 +1818,7 @@ void DrawRectOpt32(const void *destOrg, int destWidth, int destHeight, int destP
|
||||||
uint32_t stepV = (int32_t)(fstepV * 0x1000000);
|
uint32_t stepV = (int32_t)(fstepV * 0x1000000);
|
||||||
|
|
||||||
uint32_t posV = startV;
|
uint32_t posV = startV;
|
||||||
|
y1 = MIN(y1, thread->numa_end_y);
|
||||||
int num_cores = thread->num_cores;
|
int num_cores = thread->num_cores;
|
||||||
int skip = thread->skipped_by_thread(y0);
|
int skip = thread->skipped_by_thread(y0);
|
||||||
posV += skip * stepV;
|
posV += skip * stepV;
|
||||||
|
|
|
@ -46,13 +46,13 @@ void OriginalMainExcept(int argc, char** argv)
|
||||||
{
|
{
|
||||||
OriginalMainTry(argc, argv);
|
OriginalMainTry(argc, argv);
|
||||||
}
|
}
|
||||||
catch(const CDoomError& error)
|
catch(const std::exception& error)
|
||||||
{
|
{
|
||||||
const char* const message = error.GetMessage();
|
const char* const message = error.what();
|
||||||
|
|
||||||
if (NULL != message)
|
if (NULL != message)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s\n", message);
|
if (strcmp(message, "NoRunExit")) fprintf(stderr, "%s\n", message);
|
||||||
Mac_I_FatalError(message);
|
Mac_I_FatalError(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ TArray<FString> I_GetSteamPath()
|
||||||
{
|
{
|
||||||
SteamInstallFolders = ParseSteamRegistry(regPath);
|
SteamInstallFolders = ParseSteamRegistry(regPath);
|
||||||
}
|
}
|
||||||
catch(class CDoomError &error)
|
catch(class CRecoverableError &error)
|
||||||
{
|
{
|
||||||
// If we can't parse for some reason just pretend we can't find anything.
|
// If we can't parse for some reason just pretend we can't find anything.
|
||||||
return result;
|
return result;
|
||||||
|
@ -201,7 +201,7 @@ TArray<FString> I_GetSteamPath()
|
||||||
{
|
{
|
||||||
SteamInstallFolders = ParseSteamRegistry(regPath);
|
SteamInstallFolders = ParseSteamRegistry(regPath);
|
||||||
}
|
}
|
||||||
catch(class CDoomError &error)
|
catch(class CRecoverableError &error)
|
||||||
{
|
{
|
||||||
// If we can't parse for some reason just pretend we can't find anything.
|
// If we can't parse for some reason just pretend we can't find anything.
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
|
#include <thread>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
struct ticcmd_t;
|
struct ticcmd_t;
|
||||||
struct WadStuff;
|
struct WadStuff;
|
||||||
|
@ -170,4 +172,8 @@ static inline char *strlwr(char *str)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int I_GetNumaNodeCount() { return 1; }
|
||||||
|
inline int I_GetNumaNodeThreadCount(int numaNode) { return std::max<int>(std::thread::hardware_concurrency(), 1); }
|
||||||
|
inline void I_SetThreadNumaNode(std::thread &thread, int numaNode) { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -258,11 +258,11 @@ int main (int argc, char **argv)
|
||||||
C_InitConsole (80*8, 25*8, false);
|
C_InitConsole (80*8, 25*8, false);
|
||||||
D_DoomMain ();
|
D_DoomMain ();
|
||||||
}
|
}
|
||||||
catch (class CDoomError &error)
|
catch (std::exception &error)
|
||||||
{
|
{
|
||||||
I_ShutdownJoysticks();
|
I_ShutdownJoysticks();
|
||||||
if (error.GetMessage ())
|
if (error.what () && strcmp(error.what(), "NoRunExit"))
|
||||||
fprintf (stderr, "%s\n", error.GetMessage ());
|
fprintf (stderr, "%s\n", error.what ());
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
Mac_I_FatalError(error.GetMessage());
|
Mac_I_FatalError(error.GetMessage());
|
||||||
|
|
|
@ -174,7 +174,11 @@ void DrawerThreads::StartThreads()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(threads_mutex);
|
std::unique_lock<std::mutex> lock(threads_mutex);
|
||||||
|
|
||||||
int num_threads = std::thread::hardware_concurrency();
|
int num_numathreads = 0;
|
||||||
|
for (int i = 0; i < I_GetNumaNodeCount(); i++)
|
||||||
|
num_numathreads += I_GetNumaNodeThreadCount(i);
|
||||||
|
|
||||||
|
int num_threads = num_numathreads;
|
||||||
if (num_threads == 0)
|
if (num_threads == 0)
|
||||||
num_threads = 4;
|
num_threads = 4;
|
||||||
|
|
||||||
|
@ -189,13 +193,41 @@ void DrawerThreads::StartThreads()
|
||||||
|
|
||||||
threads.resize(num_threads);
|
threads.resize(num_threads);
|
||||||
|
|
||||||
for (int i = 0; i < num_threads; i++)
|
if (num_threads == num_numathreads)
|
||||||
{
|
{
|
||||||
DrawerThreads *queue = this;
|
int curThread = 0;
|
||||||
DrawerThread *thread = &threads[i];
|
for (int numaNode = 0; numaNode < I_GetNumaNodeCount(); numaNode++)
|
||||||
thread->core = i;
|
{
|
||||||
thread->num_cores = num_threads;
|
for (int i = 0; i < I_GetNumaNodeThreadCount(numaNode); i++)
|
||||||
thread->thread = std::thread([=]() { queue->WorkerMain(thread); });
|
{
|
||||||
|
DrawerThreads *queue = this;
|
||||||
|
DrawerThread *thread = &threads[curThread++];
|
||||||
|
thread->core = i;
|
||||||
|
thread->num_cores = I_GetNumaNodeThreadCount(numaNode);
|
||||||
|
thread->numa_node = numaNode;
|
||||||
|
thread->num_numa_nodes = I_GetNumaNodeCount();
|
||||||
|
thread->numa_start_y = numaNode * viewheight / I_GetNumaNodeCount();
|
||||||
|
thread->numa_end_y = (numaNode + 1) * viewheight / I_GetNumaNodeCount();
|
||||||
|
thread->thread = std::thread([=]() { queue->WorkerMain(thread); });
|
||||||
|
I_SetThreadNumaNode(thread->thread, numaNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < num_threads; i++)
|
||||||
|
{
|
||||||
|
DrawerThreads *queue = this;
|
||||||
|
DrawerThread *thread = &threads[i];
|
||||||
|
thread->core = i;
|
||||||
|
thread->num_cores = num_threads;
|
||||||
|
thread->numa_node = 0;
|
||||||
|
thread->num_numa_nodes = 1;
|
||||||
|
thread->numa_start_y = 0;
|
||||||
|
thread->numa_end_y = viewheight;
|
||||||
|
thread->thread = std::thread([=]() { queue->WorkerMain(thread); });
|
||||||
|
I_SetThreadNumaNode(thread->thread, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,4 +288,7 @@ void MemcpyCommand::Execute(DrawerThread *thread)
|
||||||
d += dstep;
|
d += dstep;
|
||||||
s += sstep;
|
s += sstep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thread->numa_start_y = thread->numa_node * viewheight / thread->num_numa_nodes;
|
||||||
|
thread->numa_end_y = (thread->numa_node + 1) * viewheight / thread->num_numa_nodes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,16 @@ public:
|
||||||
// Number of active threads
|
// Number of active threads
|
||||||
int num_cores = 1;
|
int num_cores = 1;
|
||||||
|
|
||||||
|
// NUMA node this thread belongs to
|
||||||
|
int numa_node = 0;
|
||||||
|
|
||||||
|
// Number of active NUMA nodes
|
||||||
|
int num_numa_nodes = 1;
|
||||||
|
|
||||||
|
// Active range for the numa block the cores are part of
|
||||||
|
int numa_start_y = 0;
|
||||||
|
int numa_end_y = 0;
|
||||||
|
|
||||||
// Working buffer used by the tilted (sloped) span drawer
|
// Working buffer used by the tilted (sloped) span drawer
|
||||||
const uint8_t *tiltlighting[MAXWIDTH];
|
const uint8_t *tiltlighting[MAXWIDTH];
|
||||||
|
|
||||||
|
@ -57,19 +67,21 @@ public:
|
||||||
// Checks if a line is rendered by this thread
|
// Checks if a line is rendered by this thread
|
||||||
bool line_skipped_by_thread(int line)
|
bool line_skipped_by_thread(int line)
|
||||||
{
|
{
|
||||||
return line % num_cores != core;
|
return line < numa_start_y || line >= numa_end_y || line % num_cores != core;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The number of lines to skip to reach the first line to be rendered by this thread
|
// The number of lines to skip to reach the first line to be rendered by this thread
|
||||||
int skipped_by_thread(int first_line)
|
int skipped_by_thread(int first_line)
|
||||||
{
|
{
|
||||||
int core_skip = (num_cores - (first_line - core) % num_cores) % num_cores;
|
int clip_first_line = MAX(first_line, numa_start_y);
|
||||||
return core_skip;
|
int core_skip = (num_cores - (clip_first_line - core) % num_cores) % num_cores;
|
||||||
|
return clip_first_line + core_skip - first_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The number of lines to be rendered by this thread
|
// The number of lines to be rendered by this thread
|
||||||
int count_for_thread(int first_line, int count)
|
int count_for_thread(int first_line, int count)
|
||||||
{
|
{
|
||||||
|
count = MIN(count, numa_end_y - first_line);
|
||||||
int c = (count - skipped_by_thread(first_line) + num_cores - 1) / num_cores;
|
int c = (count - skipped_by_thread(first_line) + num_cores - 1) / num_cores;
|
||||||
return MAX(c, 0);
|
return MAX(c, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1048,21 +1048,22 @@ void DoMain (HINSTANCE hInstance)
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
catch (class CDoomError &error)
|
catch (std::exception &error)
|
||||||
{
|
{
|
||||||
I_ShutdownGraphics ();
|
I_ShutdownGraphics ();
|
||||||
RestoreConView ();
|
RestoreConView ();
|
||||||
S_StopMusic(true);
|
S_StopMusic(true);
|
||||||
I_FlushBufferedConsoleStuff();
|
I_FlushBufferedConsoleStuff();
|
||||||
if (error.GetMessage ())
|
auto msg = error.what();
|
||||||
|
if (strcmp(msg, "NoRunExit"))
|
||||||
{
|
{
|
||||||
if (!batchrun)
|
if (!batchrun)
|
||||||
{
|
{
|
||||||
ShowErrorPane(error.GetMessage());
|
ShowErrorPane(msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Printf("%s\n", error.GetMessage());
|
Printf("%s\n", msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit (-1);
|
exit (-1);
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <process.h>
|
#include <process.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -1470,3 +1471,76 @@ int _stat64i32(const char *path, struct _stat64i32 *buffer)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct NumaNode
|
||||||
|
{
|
||||||
|
uint64_t affinityMask = 0;
|
||||||
|
int threadCount = 0;
|
||||||
|
};
|
||||||
|
static TArray<NumaNode> numaNodes;
|
||||||
|
|
||||||
|
static void SetupNumaNodes()
|
||||||
|
{
|
||||||
|
if (numaNodes.Size() == 0)
|
||||||
|
{
|
||||||
|
// Query processors in the system
|
||||||
|
DWORD_PTR processMask = 0, systemMask = 0;
|
||||||
|
BOOL result = GetProcessAffinityMask(GetCurrentProcess(), &processMask, &systemMask);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
// Find the numa node each processor belongs to
|
||||||
|
std::map<int, NumaNode> nodes;
|
||||||
|
for (int i = 0; i < sizeof(DWORD_PTR) * 8; i++)
|
||||||
|
{
|
||||||
|
DWORD_PTR processorMask = (((DWORD_PTR)1) << i);
|
||||||
|
if (processMask & processorMask)
|
||||||
|
{
|
||||||
|
UCHAR nodeNumber = 0;
|
||||||
|
result = GetNumaProcessorNode(i, &nodeNumber);
|
||||||
|
if (nodeNumber != 0xff)
|
||||||
|
{
|
||||||
|
nodes[nodeNumber].affinityMask |= (uint64_t)processorMask;
|
||||||
|
nodes[nodeNumber].threadCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert map to a list
|
||||||
|
for (const auto &it : nodes)
|
||||||
|
{
|
||||||
|
numaNodes.Push(it.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to a single node if something went wrong
|
||||||
|
if (numaNodes.Size() == 0)
|
||||||
|
{
|
||||||
|
NumaNode node;
|
||||||
|
node.threadCount = std::thread::hardware_concurrency();
|
||||||
|
if (node.threadCount == 0)
|
||||||
|
node.threadCount = 1;
|
||||||
|
numaNodes.Push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int I_GetNumaNodeCount()
|
||||||
|
{
|
||||||
|
SetupNumaNodes();
|
||||||
|
return numaNodes.Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int I_GetNumaNodeThreadCount(int numaNode)
|
||||||
|
{
|
||||||
|
SetupNumaNodes();
|
||||||
|
return numaNodes[numaNode].threadCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_SetThreadNumaNode(std::thread &thread, int numaNode)
|
||||||
|
{
|
||||||
|
if (numaNodes.Size() > 1)
|
||||||
|
{
|
||||||
|
HANDLE handle = (HANDLE)thread.native_handle();
|
||||||
|
SetThreadAffinityMask(handle, (DWORD_PTR)numaNodes[numaNode].affinityMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#define __I_SYSTEM__
|
#define __I_SYSTEM__
|
||||||
|
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
struct ticcmd_t;
|
struct ticcmd_t;
|
||||||
struct WadStuff;
|
struct WadStuff;
|
||||||
|
@ -186,4 +187,8 @@ inline int I_FindAttr(findstate_t *fileinfo)
|
||||||
#define FA_DIREC 0x00000010
|
#define FA_DIREC 0x00000010
|
||||||
#define FA_ARCH 0x00000020
|
#define FA_ARCH 0x00000020
|
||||||
|
|
||||||
|
int I_GetNumaNodeCount();
|
||||||
|
int I_GetNumaNodeThreadCount(int numaNode);
|
||||||
|
void I_SetThreadNumaNode(std::thread &thread, int numaNode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,6 +5,7 @@ layout(location = 2) in vec4 aColor;
|
||||||
#ifndef SIMPLE // we do not need these for simple shaders
|
#ifndef SIMPLE // we do not need these for simple shaders
|
||||||
layout(location = 3) in vec4 aVertex2;
|
layout(location = 3) in vec4 aVertex2;
|
||||||
layout(location = 4) in vec4 aNormal;
|
layout(location = 4) in vec4 aNormal;
|
||||||
|
layout(location = 5) in vec4 aNormal2;
|
||||||
out vec4 pixelpos;
|
out vec4 pixelpos;
|
||||||
out vec3 glowdist;
|
out vec3 glowdist;
|
||||||
out vec3 gradientdist;
|
out vec3 gradientdist;
|
||||||
|
@ -62,7 +63,7 @@ void main()
|
||||||
gl_ClipDistance[4] = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z);
|
gl_ClipDistance[4] = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
vWorldNormal = NormalModelMatrix * vec4(normalize(aNormal.xyz), 1.0);
|
vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0);
|
||||||
vEyeNormal = NormalViewMatrix * vWorldNormal;
|
vEyeNormal = NormalViewMatrix * vWorldNormal;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue