Beispiel #1
0
	bool NvApi::initAftermath(const ID3D12Device* _device, const ID3D12CommandList* _commandList)
	{
		if (loadAftermath() )
		{
			int32_t result;
			result = nvAftermathDx12Initialize(0x13, 1, _device);
			if (1 == result)
			{
				result = nvAftermathDx12CreateContextHandle(_commandList, &m_aftermathHandle);
				BX_WARN(1 == result, "NV Aftermath: nvAftermathDx12CreateContextHandle failed %x", result);

				if (1 == result)
				{
					return true;
				}
			}
			else
			{
				switch (result)
				{
				case int32_t(0xbad0000a): BX_TRACE("NV Aftermath: Debug layer not compatible with Aftermath."); break;
				default:                  BX_TRACE("NV Aftermath: Failed to initialize."); break;
				}
			}

			shutdownAftermath();
		}

		return false;
	}
	bool Ppapi::setInterfaces(PP_Instance _instance, const PPB_Instance* _instInterface, const PPB_Graphics3D* _graphicsInterface, PostSwapBuffersFn _postSwapBuffers)
	{
		BX_TRACE("PPAPI Interfaces");

		m_instance = _instance;
		m_instInterface = _instInterface;
		m_graphicsInterface = _graphicsInterface;
		m_instancedArrays = glGetInstancedArraysInterfacePPAPI();
		m_query = glGetQueryInterfacePPAPI();
		m_postSwapBuffers = _postSwapBuffers;

		int32_t attribs[] =
		{
			PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
			PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
			PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8,
			PP_GRAPHICS3DATTRIB_SAMPLES, 0,
			PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
			PP_GRAPHICS3DATTRIB_WIDTH, BGFX_DEFAULT_WIDTH,
			PP_GRAPHICS3DATTRIB_HEIGHT, BGFX_DEFAULT_HEIGHT,
			PP_GRAPHICS3DATTRIB_NONE
		};

		m_context = m_graphicsInterface->Create(m_instance, 0, attribs);
		if (0 == m_context)
		{
			BX_TRACE("Failed to create context!");
			return false;
		}

		m_instInterface->BindGraphics(m_instance, m_context);
		glSetCurrentContextPPAPI(m_context);
		m_graphicsInterface->SwapBuffers(m_context, naclSwapComplete);

		if (NULL != m_instancedArrays)
		{
			glVertexAttribDivisor   = naclVertexAttribDivisor;
			glDrawArraysInstanced   = naclDrawArraysInstanced;
			glDrawElementsInstanced = naclDrawElementsInstanced;
		}

		if (NULL != m_query)
		{
			glGenQueries          = naclGenQueries;
			glDeleteQueries       = naclDeleteQueries;
			glBeginQuery          = naclBeginQuery;
			glEndQuery            = naclEndQuery;
			glGetQueryObjectiv    = naclGetQueryObjectiv;
			glGetQueryObjectui64v = naclGetQueryObjectui64v;
		}

		// Prevent render thread creation.
		RenderFrame::Enum result = renderFrame();
		return RenderFrame::NoContext == result;
	}
Beispiel #3
0
void GlContext::import()
{
    BX_TRACE("Import:");
#	if BX_PLATFORM_WINDOWS
    void* glesv2 = bx::dlopen("libGLESv2.dll");
#		define GL_EXTENSION(_optional, _proto, _func, _import) \
					{ \
						if (NULL == _func) \
						{ \
							_func = (_proto)bx::dlsym(glesv2, #_import); \
							BX_TRACE("\t%p " #_func " (" #_import ")", _func); \
							BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create OpenGLES context. eglGetProcAddress(\"%s\")", #_import); \
						} \
					}
#	else
#		define GL_EXTENSION(_optional, _proto, _func, _import) \
					{ \
						if (NULL == _func) \
						{ \
							_func = (_proto)eglGetProcAddress(#_import); \
							BX_TRACE("\t%p " #_func " (" #_import ")", _func); \
							BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create OpenGLES context. eglGetProcAddress(\"%s\")", #_import); \
						} \
					}
#	endif // BX_PLATFORM_
#	include "glimports.h"
}
Beispiel #4
0
	bool VRImplOVR::init()
	{
		ovrResult initialized = ovr_Initialize(NULL);
		if (!OVR_SUCCESS(initialized))
		{
			BX_TRACE("Unable to initialize OVR runtime.");
			return false;
		}

		return true;
	}
Beispiel #5
0
	void GlContext::import()
	{
		BX_TRACE("Import:");
#	define GL_EXTENSION(_optional, _proto, _func, _import) \
				{ \
					if (_func == NULL) \
					{ \
						_func = (_proto)bx::dlsym(s_opengl, #_import); \
						BX_TRACE("%p " #_func " (" #_import ")", _func); \
					} \
					BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create OpenGL context. NSGLGetProcAddress(\"%s\")", #_import); \
				}
#	include "glimports.h"
	}
Beispiel #6
0
/*______________________________________________________________________________
[]                                                                            []
[]                                                                            []
[]` BX_VBN_Delete                                                             []             
[]                                                                            []
[]____________________________________________________________________________[]
*/
BX_RESULT
BX_VBN_Delete(BX_VBN_Args& arg)
{
	if (!CheckAdminPassword(arg.AdminPassword))
		return BXE_BadAdminPassword;
	
	if (!OC_Exist(OBJ_CLASS_ID_VBN, arg.objID))
		return BXE_VBN_Delete_InvalidObjectID;

	OC_VBN			oc_vbn;
	oc_vbn.Open(arg.objID);

	BX_TRACE("BX_VBN_Delete(): NOT SUPPORTED.");
	SERVER_DEBUG_ERROR("BX_VBN_Delete(): NOT SUPPORTED.");
	return BX_OK;
}
Beispiel #7
0
	bool VRImplOVR::init()
	{
		if (NULL != g_platformData.session)
		{
			return true;
		}

		ovrResult initialized = ovr_Initialize(NULL);
		if (!OVR_SUCCESS(initialized))
		{
			BX_TRACE("Unable to initialize OVR runtime.");
			return false;
		}

		return true;
	}
Beispiel #8
0
	void parse(const SpvShader& _src, SpvParseFn _fn, void* _userData, bx::Error* _err)
	{
		BX_ERROR_SCOPE(_err);

		uint32_t numBytes = uint32_t(_src.byteCode.size() );
		bx::MemoryReader reader(_src.byteCode.data(), numBytes);

		for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
		{
			SpvInstruction instruction;
			uint32_t size = read(&reader, instruction, _err);

			if (!_err->isOk() )
			{
				return;
			}

			if (size/4 != instruction.length)
			{
				BX_TRACE("read %d, expected %d, %s"
						, size/4
						, instruction.length
						, getName(instruction.opcode)
						);
				BX_ERROR_SET(_err, BGFX_SHADER_SPIRV_INVALID_INSTRUCTION, "SPIR-V: Invalid instruction.");
				return;
			}

			bool cont = _fn(token * sizeof(uint32_t), instruction, _userData);
			if (!cont)
			{
				return;
			}

			token += instruction.length;
		}
	}
Beispiel #9
0
bool compileGLSLShader(bx::CommandLine& _cmdLine, uint32_t _gles, const std::string& _code, bx::WriterI* _writer)
{
	char ch = tolower(_cmdLine.findOption('\0', "type")[0]);
	const glslopt_shader_type type = ch == 'f'
		? kGlslOptShaderFragment
		: (ch == 'c' ? kGlslOptShaderCompute : kGlslOptShaderVertex);

    glslopt_target target = kGlslTargetOpenGL;
	switch (_gles)
	{
	case BX_MAKEFOURCC('M', 'T', 'L', 0):
		target = kGlslTargetMetal;
		break;

	case 2:
		target = kGlslTargetOpenGLES20;
		break;

	case 3:
		target = kGlslTargetOpenGLES30;
		break;

	default:
		target = kGlslTargetOpenGL;
		break;
	}

	glslopt_ctx* ctx = glslopt_initialize(target);

	glslopt_shader* shader = glslopt_optimize(ctx, type, _code.c_str(), 0);

	if (!glslopt_get_status(shader) )
	{
		const char* log = glslopt_get_log(shader);
		int32_t source = 0;
		int32_t line = 0;
		int32_t column = 0;
		int32_t start = 0;
		int32_t end = INT32_MAX;

		if (3 == sscanf(log, "%u:%u(%u):", &source, &line, &column)
		&&  0 != line)
		{
			start = bx::uint32_imax(1, line-10);
			end = start + 20;
		}

		printCode(_code.c_str(), line, start, end);
		fprintf(stderr, "Error: %s\n", log);
		glslopt_cleanup(ctx);
		return false;
	}

	const char* optimizedShader = glslopt_get_output(shader);

	// Trim all directives.
	while ('#' == *optimizedShader)
	{
		optimizedShader = bx::strnl(optimizedShader);
	}

	if (0 != _gles)
	{
		char* code = const_cast<char*>(optimizedShader);
		strreplace(code, "gl_FragDepthEXT", "gl_FragDepth");

		strreplace(code, "texture2DLodEXT", "texture2DLod");
		strreplace(code, "texture2DProjLodEXT", "texture2DProjLod");
		strreplace(code, "textureCubeLodEXT", "textureCubeLod");
		strreplace(code, "texture2DGradEXT", "texture2DGrad");
		strreplace(code, "texture2DProjGradEXT", "texture2DProjGrad");
		strreplace(code, "textureCubeGradEXT", "textureCubeGrad");

		strreplace(code, "shadow2DEXT", "shadow2D");
		strreplace(code, "shadow2DProjEXT", "shadow2DProj");
	}

	UniformArray uniforms;

	{
		const char* parse = optimizedShader;

		while (NULL != parse
			&&  *parse != '\0')
		{
			parse = bx::strws(parse);
			const char* eol = strchr(parse, ';');
			if (NULL != eol)
			{
				const char* qualifier = parse;
				parse = bx::strws(bx::strword(parse) );

				if (0 == strncmp(qualifier, "attribute", 9)
				||  0 == strncmp(qualifier, "varying", 7) )
				{
					// skip attributes and varyings.
					parse = eol + 1;
					continue;
				}

				if (0 != strncmp(qualifier, "uniform", 7) )
				{
					// end if there is no uniform keyword.
					parse = NULL;
					continue;
				}

				const char* precision = NULL;
				const char* typen = parse;

				if (0 == strncmp(typen, "lowp", 4)
				||  0 == strncmp(typen, "mediump", 7)
				||  0 == strncmp(typen, "highp", 5) )
				{
					precision = typen;
					typen = parse = bx::strws(bx::strword(parse) );
				}

				BX_UNUSED(precision);

				char uniformType[256];
				parse = bx::strword(parse);

				if (0 == strncmp(typen, "sampler", 7) )
				{
					strcpy(uniformType, "int");
				}
				else
				{
					bx::strlcpy(uniformType, typen, parse-typen+1);
				}

				const char* name = parse = bx::strws(parse);

				char uniformName[256];
				uint8_t num = 1;
				const char* array = bx::strnstr(name, "[", eol-parse);
				if (NULL != array)
				{
					bx::strlcpy(uniformName, name, array-name+1);

					char arraySize[32];
					const char* end = bx::strnstr(array, "]", eol-array);
					bx::strlcpy(arraySize, array+1, end-array);
					num = atoi(arraySize);
				}
				else
				{
					bx::strlcpy(uniformName, name, eol-name+1);
				}

				Uniform un;
				un.type = nameToUniformTypeEnum(uniformType);

				if (UniformType::Count != un.type)
				{
					BX_TRACE("name: %s (type %d, num %d)", uniformName, un.type, num);

					un.name = uniformName;
					un.num = num;
					un.regIndex = 0;
					un.regCount = num;
					uniforms.push_back(un);
				}

				parse = eol + 1;
			}
		}
	}

	uint16_t count = (uint16_t)uniforms.size();
	bx::write(_writer, count);

	for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
	{
		const Uniform& un = *it;
		uint8_t nameSize = (uint8_t)un.name.size();
		bx::write(_writer, nameSize);
		bx::write(_writer, un.name.c_str(), nameSize);
		uint8_t uniformType = un.type;
		bx::write(_writer, uniformType);
		bx::write(_writer, un.num);
		bx::write(_writer, un.regIndex);
		bx::write(_writer, un.regCount);

		BX_TRACE("%s, %s, %d, %d, %d"
			, un.name.c_str()
			, getUniformTypeName(un.type)
			, un.num
			, un.regIndex
			, un.regCount
			);
	}

	uint32_t shaderSize = (uint32_t)strlen(optimizedShader);
	bx::write(_writer, shaderSize);
	bx::write(_writer, optimizedShader, shaderSize);
	uint8_t nul = 0;
	bx::write(_writer, nul);

	glslopt_cleanup(ctx);

	return true;
}
Beispiel #10
0
	static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer)
	{
		char ch = _options.shaderType;
		const glslopt_shader_type type = ch == 'f'
			? kGlslOptShaderFragment
			: (ch == 'c' ? kGlslOptShaderCompute : kGlslOptShaderVertex);

		glslopt_target target = kGlslTargetOpenGL;
		switch (_version)
		{
		case BX_MAKEFOURCC('M', 'T', 'L', 0):
			target = kGlslTargetMetal;
			break;

		case 2:
			target = kGlslTargetOpenGLES20;
			break;

		case 3:
			target = kGlslTargetOpenGLES30;
			break;

		default:
			target = kGlslTargetOpenGL;
			break;
		}

		glslopt_ctx* ctx = glslopt_initialize(target);

		glslopt_shader* shader = glslopt_optimize(ctx, type, _code.c_str(), 0);

		if (!glslopt_get_status(shader) )
		{
			const char* log = glslopt_get_log(shader);
			int32_t source  = 0;
			int32_t line    = 0;
			int32_t column  = 0;
			int32_t start   = 0;
			int32_t end     = INT32_MAX;

			bool found = false
				|| 3 == sscanf(log, "%u:%u(%u):", &source, &line, &column)
				|| 2 == sscanf(log, "(%u,%u):", &line, &column)
				;

			if (found
			&&  0 != line)
			{
				start = bx::uint32_imax(1, line-10);
				end   = start + 20;
			}

			printCode(_code.c_str(), line, start, end, column);
			fprintf(stderr, "Error: %s\n", log);
			glslopt_shader_delete(shader);
			glslopt_cleanup(ctx);
			return false;
		}

		const char* optimizedShader = glslopt_get_output(shader);

		// Trim all directives.
		while ('#' == *optimizedShader)
		{
			optimizedShader = bx::strnl(optimizedShader);
		}

		{
			char* code = const_cast<char*>(optimizedShader);
			strReplace(code, "gl_FragDepthEXT", "gl_FragDepth");

			strReplace(code, "texture2DLodARB", "texture2DLod");
			strReplace(code, "texture2DLodEXT", "texture2DLod");
			strReplace(code, "texture2DGradARB", "texture2DGrad");
			strReplace(code, "texture2DGradEXT", "texture2DGrad");

			strReplace(code, "textureCubeLodARB", "textureCubeLod");
			strReplace(code, "textureCubeLodEXT", "textureCubeLod");
			strReplace(code, "textureCubeGradARB", "textureCubeGrad");
			strReplace(code, "textureCubeGradEXT", "textureCubeGrad");

			strReplace(code, "texture2DProjLodARB", "texture2DProjLod");
			strReplace(code, "texture2DProjLodEXT", "texture2DProjLod");
			strReplace(code, "texture2DProjGradARB", "texture2DProjGrad");
			strReplace(code, "texture2DProjGradEXT", "texture2DProjGrad");

			strReplace(code, "shadow2DARB", "shadow2D");
			strReplace(code, "shadow2DEXT", "shadow2D");
			strReplace(code, "shadow2DProjARB", "shadow2DProj");
			strReplace(code, "shadow2DProjEXT", "shadow2DProj");
		}

		UniformArray uniforms;

		if (target != kGlslTargetMetal)
		{
			const char* parse = optimizedShader;

			while (NULL != parse
				&&  *parse != '\0')
			{
				parse = bx::strws(parse);
				const char* eol = bx::strFind(parse, ';');
				if (NULL != eol)
				{
					const char* qualifier = parse;
					parse = bx::strws(bx::strSkipWord(parse) );

					if (0 == bx::strCmp(qualifier, "attribute", 9)
					||  0 == bx::strCmp(qualifier, "varying",   7)
					||  0 == bx::strCmp(qualifier, "in",        2)
					||  0 == bx::strCmp(qualifier, "out",       3)
					   )
					{
						// skip attributes and varyings.
						parse = eol + 1;
						continue;
					}

					if (0 == bx::strCmp(parse, "tmpvar", 6) )
					{
						// skip temporaries
						parse = eol + 1;
						continue;
					}

					if (0 != bx::strCmp(qualifier, "uniform", 7) )
					{
						// end if there is no uniform keyword.
						parse = NULL;
						continue;
					}

					const char* precision = NULL;
					const char* typen = parse;

					if (0 == bx::strCmp(typen, "lowp", 4)
					||  0 == bx::strCmp(typen, "mediump", 7)
					||  0 == bx::strCmp(typen, "highp", 5) )
					{
						precision = typen;
						typen = parse = bx::strws(bx::strSkipWord(parse) );
					}

					BX_UNUSED(precision);

					char uniformType[256];
					parse = bx::strSkipWord(parse);

					if (0 == bx::strCmp(typen, "sampler", 7) )
					{
						bx::strCopy(uniformType, BX_COUNTOF(uniformType), "int");
					}
					else
					{
						bx::strCopy(uniformType, int32_t(parse-typen+1), typen);
					}

					const char* name = parse = bx::strws(parse);

					char uniformName[256];
					uint8_t num = 1;
					const char* array = bx::strFind(bx::StringView(name, int32_t(eol-parse) ), "[");
					if (NULL != array)
					{
						bx::strCopy(uniformName, int32_t(array-name+1), name);

						char arraySize[32];
						const char* end = bx::strFind(bx::StringView(array, int32_t(eol-array) ), "]");
						bx::strCopy(arraySize, int32_t(end-array), array+1);
						num = uint8_t(atoi(arraySize) );
					}
					else
					{
						bx::strCopy(uniformName, int32_t(eol-name+1), name);
					}

					Uniform un;
					un.type = nameToUniformTypeEnum(uniformType);

					if (UniformType::Count != un.type)
					{
						BX_TRACE("name: %s (type %d, num %d)", uniformName, un.type, num);

						un.name = uniformName;
						un.num = num;
						un.regIndex = 0;
						un.regCount = num;
						uniforms.push_back(un);
					}

					parse = eol + 1;
				}
			}
		}
		else
		{
			const char* parse = bx::strFind(optimizedShader, "struct xlatMtlShaderUniform {");
			const char* end   = parse;
			if (NULL != parse)
			{
				parse += bx::strLen("struct xlatMtlShaderUniform {");
				end   =  bx::strFind(parse, "};");
			}

			while ( parse < end
			&&     *parse != '\0')
			{
				parse = bx::strws(parse);
				const char* eol = bx::strFind(parse, ';');
				if (NULL != eol)
				{
					const char* typen = parse;

					char uniformType[256];
					parse = bx::strSkipWord(parse);
					bx::strCopy(uniformType, int32_t(parse-typen+1), typen);
					const char* name = parse = bx::strws(parse);

					char uniformName[256];
					uint8_t num = 1;
					const char* array = bx::strFind(bx::StringView(name, int32_t(eol-parse) ), "[");
					if (NULL != array)
					{
						bx::strCopy(uniformName, int32_t(array-name+1), name);

						char arraySize[32];
						const char* arrayEnd = bx::strFind(bx::StringView(array, int32_t(eol-array) ), "]");
						bx::strCopy(arraySize, int32_t(arrayEnd-array), array+1);
						num = uint8_t(atoi(arraySize) );
					}
					else
					{
						bx::strCopy(uniformName, int32_t(eol-name+1), name);
					}

					Uniform un;
					un.type = nameToUniformTypeEnum(uniformType);

					if (UniformType::Count != un.type)
					{
						BX_TRACE("name: %s (type %d, num %d)", uniformName, un.type, num);

						un.name = uniformName;
						un.num = num;
						un.regIndex = 0;
						un.regCount = num;
						uniforms.push_back(un);
					}

					parse = eol + 1;
				}
			}
		}

		uint16_t count = (uint16_t)uniforms.size();
		bx::write(_writer, count);

		for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
		{
			const Uniform& un = *it;
			uint8_t nameSize = (uint8_t)un.name.size();
			bx::write(_writer, nameSize);
			bx::write(_writer, un.name.c_str(), nameSize);
			uint8_t uniformType = uint8_t(un.type);
			bx::write(_writer, uniformType);
			bx::write(_writer, un.num);
			bx::write(_writer, un.regIndex);
			bx::write(_writer, un.regCount);

			BX_TRACE("%s, %s, %d, %d, %d"
				, un.name.c_str()
				, getUniformTypeName(un.type)
				, un.num
				, un.regIndex
				, un.regCount
				);
		}

		uint32_t shaderSize = (uint32_t)bx::strLen(optimizedShader);
		bx::write(_writer, shaderSize);
		bx::write(_writer, optimizedShader, shaderSize);
		uint8_t nul = 0;
		bx::write(_writer, nul);

		if (_options.disasm )
		{
			std::string disasmfp = _options.outputFilePath + ".disasm";
			writeFile(disasmfp.c_str(), optimizedShader, shaderSize);
		}

		glslopt_shader_delete(shader);
		glslopt_cleanup(ctx);

		return true;
	}
Beispiel #11
0
int main(int _argc, const char* _argv[])
{
	bx::CommandLine cmdLine(_argc, _argv);

	const char* filePath = cmdLine.findOption('f');
	if (NULL == filePath)
	{
		help("Input file name must be specified.");
		return EXIT_FAILURE;
	}

	const char* outFilePath = cmdLine.findOption('o');
	if (NULL == outFilePath)
	{
		help("Output file name must be specified.");
		return EXIT_FAILURE;
	}

	float scale = 1.0f;
	const char* scaleArg = cmdLine.findOption('s', "scale");
	if (NULL != scaleArg)
	{
		scale = (float)atof(scaleArg);
	}

	cmdLine.hasArg(s_obbSteps, '\0', "obb");
	s_obbSteps = bx::uint32_min(bx::uint32_max(s_obbSteps, 1), 90);

	uint32_t packNormal = 0;
	cmdLine.hasArg(packNormal, '\0', "packnormal");

	uint32_t packUv = 0;
	cmdLine.hasArg(packUv, '\0', "packuv");
	
	bool ccw = cmdLine.hasArg("ccw");
	bool flipV = cmdLine.hasArg("flipv");
	bool hasTangent = cmdLine.hasArg("tangent");

	FILE* file = fopen(filePath, "r");
	if (NULL == file)
	{
		printf("Unable to open input file '%s'.", filePath);
		exit(EXIT_FAILURE);
	}

	int64_t parseElapsed = -bx::getHPCounter();
	int64_t triReorderElapsed = 0;

	uint32_t size = (uint32_t)fsize(file);
	char* data = new char[size+1];
	size = (uint32_t)fread(data, 1, size, file);
	data[size] = '\0';
	fclose(file);

	// https://en.wikipedia.org/wiki/Wavefront_.obj_file

	Vector3Array positions;
	Vector3Array normals;
	Vector3Array texcoords;
	Index3Map indexMap;
	TriangleArray triangles;
	GroupArray groups;

	uint32_t num = 0;

	Group group;
	group.m_startTriangle = 0;
	group.m_numTriangles = 0;

	char commandLine[2048];
	uint32_t len = sizeof(commandLine);
	int argc;
	char* argv[64];
	const char* next = data;
	do
	{
		next = tokenizeCommandLine(next, commandLine, len, argc, argv, countof(argv), '\n');
		if (0 < argc)
		{
			if (0 == strcmp(argv[0], "#") )
			{
				if (2 < argc
				&&  0 == strcmp(argv[2], "polygons") )
				{
				}
			}
			else if (0 == strcmp(argv[0], "f") )
			{
				Triangle triangle;

				for (uint32_t edge = 0, numEdges = argc-1; edge < numEdges; ++edge)
				{
					Index3 index;
					index.m_texcoord = -1;
					index.m_normal = -1;
					index.m_vertexIndex = -1;

					char* vertex = argv[edge+1];
					char* texcoord = strchr(vertex, '/');
					if (NULL != texcoord)
					{
						*texcoord++ = '\0';

						char* normal = strchr(texcoord, '/');
						if (NULL != normal)
						{
							*normal++ = '\0';
							index.m_normal = atoi(normal)-1;
						}

						index.m_texcoord = atoi(texcoord)-1;
					}

					index.m_position = atoi(vertex)-1;

					uint64_t hash0 = index.m_position;
					uint64_t hash1 = uint64_t(index.m_texcoord)<<20;
					uint64_t hash2 = uint64_t(index.m_normal)<<40;
					uint64_t hash = hash0^hash1^hash2;

					std::pair<Index3Map::iterator, bool> result = indexMap.insert(std::make_pair(hash, index) );
					if (!result.second)
					{
						Index3& oldIndex = result.first->second;
						BX_UNUSED(oldIndex);
						BX_CHECK(oldIndex.m_position == index.m_position
							&& oldIndex.m_texcoord == index.m_texcoord
							&& oldIndex.m_normal == index.m_normal
							, "Hash collision!"
							);
					}

					switch (edge)
					{
					case 0:
					case 1:
					case 2:
						triangle.m_index[edge] = hash;
						if (2 == edge)
						{
							if (ccw)
							{
								std::swap(triangle.m_index[1], triangle.m_index[2]);
							}
							triangles.push_back(triangle);
						}
						break;

					default:
						if (ccw)
						{
							triangle.m_index[2] = triangle.m_index[1];
							triangle.m_index[1] = hash;
						}
						else
						{
							triangle.m_index[1] = triangle.m_index[2];
							triangle.m_index[2] = hash;
						}
						triangles.push_back(triangle);
						break;
					}
				}
			}
			else if (0 == strcmp(argv[0], "g") )
			{
				EXPECT(1 < argc);
				group.m_name = argv[1];
			}
			else if (*argv[0] == 'v')
			{
				group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
				if (0 < group.m_numTriangles)
				{
					groups.push_back(group);
					group.m_startTriangle = (uint32_t)(triangles.size() );
					group.m_numTriangles = 0;
				}

				if (0 == strcmp(argv[0], "vn") )
				{
					Vector3 normal;
					normal.x = (float)atof(argv[1]);
					normal.y = (float)atof(argv[2]);
					normal.z = (float)atof(argv[3]);

					normals.push_back(normal);
				}
				else if (0 == strcmp(argv[0], "vp") )
				{
					static bool once = true;
					if (once)
					{
						once = false;
						printf("warning: 'parameter space vertices' are unsupported.\n");
					}
				}
				else if (0 == strcmp(argv[0], "vt") )
				{
					Vector3 texcoord;
					texcoord.x = (float)atof(argv[1]);
					texcoord.y = 0.0f;
					texcoord.z = 0.0f;
					switch (argc)
					{
					case 4:
						texcoord.z = (float)atof(argv[3]);
						// fallthrough
					case 3:
						texcoord.y = (float)atof(argv[2]);
						break;

					default:
						break;
					}

					texcoords.push_back(texcoord);
				}
				else
				{
					float px = (float)atof(argv[1]);
					float py = (float)atof(argv[2]);
					float pz = (float)atof(argv[3]);
					float pw = 1.0f;
					if (argc > 4)
					{
						pw = (float)atof(argv[4]);
					}

					float invW = scale/pw;
					px *= invW;
					py *= invW;
					pz *= invW;

					Vector3 pos;
					pos.x = px;
					pos.y = py;
					pos.z = pz;

					positions.push_back(pos);
				}
			}
			else if (0 == strcmp(argv[0], "usemtl") )
			{
				std::string material(argv[1]);

				if (material != group.m_material)
				{
					group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
					if (0 < group.m_numTriangles)
					{
						groups.push_back(group);
						group.m_startTriangle = (uint32_t)(triangles.size() );
						group.m_numTriangles = 0;
					}
				}

				group.m_material = material;
			}
// unsupported tags
// 				else if (0 == strcmp(argv[0], "mtllib") )
// 				{
// 				}
// 				else if (0 == strcmp(argv[0], "o") )
// 				{
// 				}
// 				else if (0 == strcmp(argv[0], "s") )
// 				{
// 				}
		}

		++num;
	}
	while ('\0' != *next);

	group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
	if (0 < group.m_numTriangles)
	{
		groups.push_back(group);
		group.m_startTriangle = (uint32_t)(triangles.size() );
		group.m_numTriangles = 0;
	}

	delete [] data;

	int64_t now = bx::getHPCounter();
	parseElapsed += now;
	int64_t convertElapsed = -now;

	struct GroupSortByMaterial
	{
		bool operator()(const Group& _lhs, const Group& _rhs)
		{
			return _lhs.m_material < _rhs.m_material;
		}
	};

	std::sort(groups.begin(), groups.end(), GroupSortByMaterial() );

	bool hasColor = false;
	bool hasNormal;
	bool hasTexcoord;
	{
		Index3Map::const_iterator it = indexMap.begin();
		hasNormal = -1 != it->second.m_normal;
		hasTexcoord = -1 != it->second.m_texcoord;

		if (!hasTexcoord
		&&  texcoords.size() == positions.size() )
		{
			hasTexcoord = true;

			for (Index3Map::iterator it = indexMap.begin(), itEnd = indexMap.end(); it != itEnd; ++it)
			{
				it->second.m_texcoord = it->second.m_position;
			}
		}

		if (!hasNormal
		&&  normals.size() == positions.size() )
		{
			hasNormal = true;

			for (Index3Map::iterator it = indexMap.begin(), itEnd = indexMap.end(); it != itEnd; ++it)
			{
				it->second.m_normal = it->second.m_position;
			}
		}
	}

	bgfx::VertexDecl decl;
	decl.begin();
	decl.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float);

	if (hasColor)
	{
		decl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true);
	}

	if (hasTexcoord)
	{
		switch (packUv)
		{
		default:
		case 0:
			decl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float);
			break;

		case 1:
			decl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Half);
			break;
		}
	}

	if (hasNormal)
	{
		hasTangent &= hasTexcoord;

		switch (packNormal)
		{
		default:
		case 0:
			decl.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float);
			if (hasTangent)
			{
				decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Float);
			}
			break;

		case 1:
			decl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true);
			if (hasTangent)
			{
				decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true);
			}
			break;
		}
	}
	decl.end();

	uint32_t stride = decl.getStride();
	uint8_t* vertexData = new uint8_t[triangles.size() * 3 * stride];
	uint16_t* indexData = new uint16_t[triangles.size() * 3];
	int32_t numVertices = 0;
	int32_t numIndices = 0;
	int32_t numPrimitives = 0;

	uint8_t* vertices = vertexData;
	uint16_t* indices = indexData;

	std::string material = groups.begin()->m_material;

	PrimitiveArray primitives;

	bx::CrtFileWriter writer;
	if (0 != writer.open(outFilePath) )
	{
		printf("Unable to open output file '%s'.", outFilePath);
		exit(EXIT_FAILURE);
	}

	Primitive prim;
	prim.m_startVertex = 0;
	prim.m_startIndex = 0;

	uint32_t positionOffset = decl.getOffset(bgfx::Attrib::Position);
	uint32_t color0Offset = decl.getOffset(bgfx::Attrib::Color0);

	uint32_t ii = 0;
	for (GroupArray::const_iterator groupIt = groups.begin(); groupIt != groups.end(); ++groupIt, ++ii)
	{
		for (uint32_t tri = groupIt->m_startTriangle, end = tri + groupIt->m_numTriangles; tri < end; ++tri)
		{
			if (material != groupIt->m_material
			||  65533 < numVertices)
			{
				prim.m_numVertices = numVertices - prim.m_startVertex;
				prim.m_numIndices = numIndices - prim.m_startIndex;
				if (0 < prim.m_numVertices)
				{
					primitives.push_back(prim);
				}

				triReorderElapsed -= bx::getHPCounter();
				for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
				{
					const Primitive& prim = *primIt;
					triangleReorder(indexData + prim.m_startIndex, prim.m_numIndices, numVertices, 32);
				}
				triReorderElapsed += bx::getHPCounter();

				if (hasTangent)
				{
					calcTangents(vertexData, numVertices, decl, indexData, numIndices);
				}

				write(&writer, vertexData, numVertices, decl, indexData, numIndices, material, primitives);
				primitives.clear();

				for (Index3Map::iterator indexIt = indexMap.begin(); indexIt != indexMap.end(); ++indexIt)
				{
					indexIt->second.m_vertexIndex = -1;
				}

				vertices = vertexData;
				indices = indexData;
				numVertices = 0;
				numIndices = 0;
				prim.m_startVertex = 0;
				prim.m_startIndex = 0;
				++numPrimitives;

				material = groupIt->m_material;
			}

			Triangle& triangle = triangles[tri];
			for (uint32_t edge = 0; edge < 3; ++edge)
			{
				uint64_t hash = triangle.m_index[edge];
				Index3& index = indexMap[hash];
				if (index.m_vertexIndex == -1)
				{
		 			index.m_vertexIndex = numVertices++;

					float* position = (float*)(vertices + positionOffset);
					memcpy(position, &positions[index.m_position], 3*sizeof(float) );

					if (hasColor)
					{
						uint32_t* color0 = (uint32_t*)(vertices + color0Offset);
						*color0 = rgbaToAbgr(numVertices%255, numIndices%255, 0, 0xff);
					}

					if (hasTexcoord)
					{
						float uv[2];
						memcpy(uv, &texcoords[index.m_texcoord], 2*sizeof(float) );

						if (flipV)
						{
							uv[1] = -uv[1];
						}

						bgfx::vertexPack(uv, true, bgfx::Attrib::TexCoord0, decl, vertices);
					}

					if (hasNormal)
					{
						float normal[4];
						vec3Norm(normal, (float*)&normals[index.m_normal]);
						bgfx::vertexPack(normal, true, bgfx::Attrib::Normal, decl, vertices);
					}

					vertices += stride;
				}

				*indices++ = (uint16_t)index.m_vertexIndex;
				++numIndices;
			}
		}

		if (0 < numVertices)
		{
			prim.m_numVertices = numVertices - prim.m_startVertex;
			prim.m_numIndices = numIndices - prim.m_startIndex;
			prim.m_name = groupIt->m_name;
			primitives.push_back(prim);
			prim.m_startVertex = numVertices;
			prim.m_startIndex = numIndices;
		}

		BX_TRACE("%3d: s %5d, n %5d, %s\n"
			, ii
			, groupIt->m_startTriangle
			, groupIt->m_numTriangles
			, groupIt->m_material.c_str()
			);
	}

	if (0 < primitives.size() )
	{
		triReorderElapsed -= bx::getHPCounter();
		for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
		{
			const Primitive& prim = *primIt;
			triangleReorder(indexData + prim.m_startIndex, prim.m_numIndices, numVertices, 32);
		}
		triReorderElapsed += bx::getHPCounter();

		if (hasTangent)
		{
			calcTangents(vertexData, numVertices, decl, indexData, numIndices);
		}

		write(&writer, vertexData, numVertices, decl, indexData, numIndices, material, primitives);
	}

	printf("size: %d\n", uint32_t(writer.seek() ) );
	writer.close();

	delete [] indexData;
	delete [] vertexData;

	now = bx::getHPCounter();
	convertElapsed += now;

	printf("parse %f [s]\ntri reorder %f [s]\nconvert %f [s]\n# %d, g %d, p %d, v %d, i %d\n"
		, double(parseElapsed)/bx::getHPFrequency()
		, double(triReorderElapsed)/bx::getHPFrequency()
		, double(convertElapsed)/bx::getHPFrequency()
		, num
		, uint32_t(groups.size() )
		, numPrimitives
		, numVertices
		, numIndices
		);

	return EXIT_SUCCESS;
}
Beispiel #12
0
void GlContext::create(uint32_t _width, uint32_t _height)
{
    BX_UNUSED(_width, _height);
    XLockDisplay(s_display);

    int major, minor;
    bool version = glXQueryVersion(s_display, &major, &minor);
    BGFX_FATAL(version, Fatal::UnableToInitialize, "Failed to query GLX version");
    BGFX_FATAL( (major == 1 && minor >= 2) || major > 1
                , Fatal::UnableToInitialize
                , "GLX version is not >=1.2 (%d.%d)."
                , major
                , minor
              );

    int32_t screen = DefaultScreen(s_display);

    const char* extensions = glXQueryExtensionsString(s_display, screen);
    BX_TRACE("GLX extensions:");
    dumpExtensions(extensions);

    const int attrsGlx[] =
    {
        GLX_RENDER_TYPE, GLX_RGBA_BIT,
        GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
        GLX_DOUBLEBUFFER, true,
        GLX_RED_SIZE, 8,
        GLX_BLUE_SIZE, 8,
        GLX_GREEN_SIZE, 8,
//			GLX_ALPHA_SIZE, 8,
        GLX_DEPTH_SIZE, 24,
        GLX_STENCIL_SIZE, 8,
        0,
    };

    // Find suitable config
    GLXFBConfig bestConfig = NULL;

    int numConfigs;
    GLXFBConfig* configs = glXChooseFBConfig(s_display, screen, attrsGlx, &numConfigs);

    BX_TRACE("glX num configs %d", numConfigs);

    XVisualInfo* visualInfo = NULL;
    for (int ii = 0; ii < numConfigs; ++ii)
    {
        visualInfo = glXGetVisualFromFBConfig(s_display, configs[ii]);
        if (NULL != visualInfo)
        {
            BX_TRACE("---");
            bool valid = true;
            for (uint32_t attr = 6; attr < BX_COUNTOF(attrsGlx)-1 && attrsGlx[attr] != None; attr += 2)
            {
                int value;
                glXGetFBConfigAttrib(s_display, configs[ii], attrsGlx[attr], &value);
                BX_TRACE("glX %d/%d %2d: %4x, %8x (%8x%s)"
                         , ii
                         , numConfigs
                         , attr/2
                         , attrsGlx[attr]
                         , value
                         , attrsGlx[attr + 1]
                         , value < attrsGlx[attr + 1] ? " *" : ""
                        );

                if (value < attrsGlx[attr + 1])
                {
                    valid = false;
#if !BGFX_CONFIG_DEBUG
                    break;
#endif // BGFX_CONFIG_DEBUG
                }
            }

            if (valid)
            {
                bestConfig = configs[ii];
                BX_TRACE("Best config %d.", ii);
                break;
            }
        }

        XFree(visualInfo);
        visualInfo = NULL;
    }

    XFree(configs);
    BGFX_FATAL(visualInfo, Fatal::UnableToInitialize, "Failed to find a suitable X11 display configuration.");

    BX_TRACE("Create GL 2.1 context.");
    m_context = glXCreateContext(s_display, visualInfo, 0, GL_TRUE);
    BGFX_FATAL(NULL != m_context, Fatal::UnableToInitialize, "Failed to create GL 2.1 context.");

    XFree(visualInfo);

#if BGFX_CONFIG_RENDERER_OPENGL >= 31
    glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress( (const GLubyte*)"glXCreateContextAttribsARB");

    if (NULL != glXCreateContextAttribsARB)
    {
        BX_TRACE("Create GL 3.1 context.");
        const int contextAttrs[] =
        {
            GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
            GLX_CONTEXT_MINOR_VERSION_ARB, 1,
            GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
            0,
        };

        GLXContext context = glXCreateContextAttribsARB(s_display, bestConfig, 0, true, contextAttrs);

        if (NULL != context)
        {
            glXDestroyContext(s_display, m_context);
            m_context = context;
        }
    }
#else
    BX_UNUSED(bestConfig);
#endif // BGFX_CONFIG_RENDERER_OPENGL >= 31

    XUnlockDisplay(s_display);

    import();

    glXMakeCurrent(s_display, s_window, m_context);

    glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress( (const GLubyte*)"glXSwapIntervalEXT");
    if (NULL != glXSwapIntervalEXT)
    {
        BX_TRACE("Using glXSwapIntervalEXT.");
        glXSwapIntervalEXT(s_display, s_window, 0);
    }
    else
    {
        glXSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress( (const GLubyte*)"glXSwapIntervalMESA");
        if (NULL != glXSwapIntervalMESA)
        {
            BX_TRACE("Using glXSwapIntervalMESA.");
            glXSwapIntervalMESA(0);
        }
        else
        {
            glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddress( (const GLubyte*)"glXSwapIntervalSGI");
            if (NULL != glXSwapIntervalSGI)
            {
                BX_TRACE("Using glXSwapIntervalSGI.");
                glXSwapIntervalSGI(0);
            }
        }
    }

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glXSwapBuffers(s_display, s_window);
}
Beispiel #13
0
	void GlContext::create(uint32_t _width, uint32_t _height)
	{
		BX_UNUSED(_width, _height);
		BX_TRACE("GlContext::create");
	}
bool getReflectionDataD3D9(ID3DBlob* _code, UniformArray& _uniforms)
{
    // see reference for magic values: https://msdn.microsoft.com/en-us/library/ff552891(VS.85).aspx
    const uint32_t D3DSIO_COMMENT = 0x0000FFFE;
    const uint32_t D3DSIO_END = 0x0000FFFF;
    const uint32_t D3DSI_OPCODE_MASK = 0x0000FFFF;
    const uint32_t D3DSI_COMMENTSIZE_MASK = 0x7FFF0000;
    const uint32_t CTAB_CONSTANT = MAKEFOURCC('C', 'T', 'A', 'B');

    // parse the shader blob for the constant table
    const size_t codeSize = _code->GetBufferSize();
    const uint32_t* ptr = (const uint32_t*)_code->GetBufferPointer();
    const uint32_t* end = (const uint32_t*)( (const uint8_t*)ptr + codeSize);
    const CTHeader* header = NULL;

    ptr++;	// first byte is shader type / version; skip it since we already know

    while (ptr < end && *ptr != D3DSIO_END)
    {
        uint32_t cur = *ptr++;
        if ( (cur & D3DSI_OPCODE_MASK) != D3DSIO_COMMENT)
        {
            continue;
        }

        // try to find CTAB comment block
        uint32_t commentSize = (cur & D3DSI_COMMENTSIZE_MASK) >> 16;
        uint32_t fourcc = *ptr;
        if (fourcc == CTAB_CONSTANT)
        {
            // found the constant table data
            header = (const CTHeader*)(ptr + 1);
            uint32_t tableSize = (commentSize - 1) * 4;
            if (tableSize < sizeof(CTHeader) || header->Size != sizeof(CTHeader) )
            {
                fprintf(stderr, "Error: Invalid constant table data\n");
                return false;
            }
            break;
        }

        // this is a different kind of comment section, so skip over it
        ptr += commentSize - 1;
    }

    if (!header)
    {
        fprintf(stderr, "Error: Could not find constant table data\n");
        return false;
    }

    const uint8_t* headerBytePtr = (const uint8_t*)header;
    const char* creator = (const char*)(headerBytePtr + header->Creator);

    BX_TRACE("Creator: %s 0x%08x", creator, header->Version);
    BX_TRACE("Num constants: %d", header->Constants);
    BX_TRACE("#   cl ty RxC   S  By Name");

    const CTInfo* ctInfoArray = (const CTInfo*)(headerBytePtr + header->ConstantInfo);
    for (uint32_t ii = 0; ii < header->Constants; ++ii)
    {
        const CTInfo& ctInfo = ctInfoArray[ii];
        const CTType& ctType = *(const CTType*)(headerBytePtr + ctInfo.TypeInfo);
        const char* name = (const char*)(headerBytePtr + ctInfo.Name);

        BX_TRACE("%3d %2d %2d [%dx%d] %d %s[%d] c%d (%d)"
                 , ii
                 , ctType.Class
                 , ctType.Type
                 , ctType.Rows
                 , ctType.Columns
                 , ctType.StructMembers
                 , name
                 , ctType.Elements
                 , ctInfo.RegisterIndex
                 , ctInfo.RegisterCount
                );

        D3D11_SHADER_TYPE_DESC desc;
        desc.Class = (D3D_SHADER_VARIABLE_CLASS)ctType.Class;
        desc.Type = (D3D_SHADER_VARIABLE_TYPE)ctType.Type;
        desc.Rows = ctType.Rows;
        desc.Columns = ctType.Columns;

        UniformType::Enum type = findUniformType(desc);
        if (UniformType::Count != type)
        {
            Uniform un;
            un.name = '$' == name[0] ? name + 1 : name;
            un.type = isSampler(desc.Type)
                      ? UniformType::Enum(BGFX_UNIFORM_SAMPLERBIT | type)
                      : type
                      ;
            un.num = (uint8_t)ctType.Elements;
            un.regIndex = ctInfo.RegisterIndex;
            un.regCount = ctInfo.RegisterCount;

            _uniforms.push_back(un);
        }
    }

    return true;
}
Beispiel #15
0
	void GlContext::create(uint32_t _width, uint32_t _height)
	{
#	if BX_PLATFORM_RPI
		bcm_host_init();
#	endif // BX_PLATFORM_RPI

		m_eglLibrary = eglOpen();

		if (NULL == g_platformData.context)
		{
#	if BX_PLATFORM_RPI
			g_platformData.ndt = EGL_DEFAULT_DISPLAY;
#	endif // BX_PLATFORM_RPI

			BX_UNUSED(_width, _height);
			EGLNativeDisplayType ndt = (EGLNativeDisplayType)g_platformData.ndt;
			EGLNativeWindowType  nwh = (EGLNativeWindowType )g_platformData.nwh;

#	if BX_PLATFORM_WINDOWS
			if (NULL == g_platformData.ndt)
			{
				ndt = GetDC( (HWND)g_platformData.nwh);
			}
#	endif // BX_PLATFORM_WINDOWS

			m_display = eglGetDisplay(ndt);
			BGFX_FATAL(m_display != EGL_NO_DISPLAY, Fatal::UnableToInitialize, "Failed to create display %p", m_display);

			EGLint major = 0;
			EGLint minor = 0;
			EGLBoolean success = eglInitialize(m_display, &major, &minor);
			BGFX_FATAL(success && major >= 1 && minor >= 3, Fatal::UnableToInitialize, "Failed to initialize %d.%d", major, minor);

			BX_TRACE("EGL info:");
			const char* clientApis = eglQueryString(m_display, EGL_CLIENT_APIS);
			BX_TRACE("   APIs: %s", clientApis); BX_UNUSED(clientApis);

			const char* vendor = eglQueryString(m_display, EGL_VENDOR);
			BX_TRACE(" Vendor: %s", vendor); BX_UNUSED(vendor);

			const char* version = eglQueryString(m_display, EGL_VERSION);
			BX_TRACE("Version: %s", version); BX_UNUSED(version);

			const char* extensions = eglQueryString(m_display, EGL_EXTENSIONS);
			BX_TRACE("Supported EGL extensions:");
			dumpExtensions(extensions);

			EGLint attrs[] =
			{
				EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,

#	if BX_PLATFORM_ANDROID
				EGL_DEPTH_SIZE, 16,
#	else
				EGL_DEPTH_SIZE, 24,
#	endif // BX_PLATFORM_
				EGL_STENCIL_SIZE, 8,

				EGL_NONE
			};

			EGLint numConfig = 0;
			success = eglChooseConfig(m_display, attrs, &m_config, 1, &numConfig);
			BGFX_FATAL(success, Fatal::UnableToInitialize, "eglChooseConfig");

#	if BX_PLATFORM_ANDROID

			EGLint format;
			eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &format);
			ANativeWindow_setBuffersGeometry( (ANativeWindow*)g_platformData.nwh, _width, _height, format);

#	elif BX_PLATFORM_RPI
			DISPMANX_DISPLAY_HANDLE_T dispmanDisplay = vc_dispmanx_display_open(0);
			DISPMANX_UPDATE_HANDLE_T  dispmanUpdate  = vc_dispmanx_update_start(0);

			VC_RECT_T dstRect = { 0, 0, int32_t(_width),        int32_t(_height)       };
			VC_RECT_T srcRect = { 0, 0, int32_t(_width)  << 16, int32_t(_height) << 16 };

			DISPMANX_ELEMENT_HANDLE_T dispmanElement = vc_dispmanx_element_add(dispmanUpdate
				, dispmanDisplay
				, 0
				, &dstRect
				, 0
				, &srcRect
				, DISPMANX_PROTECTION_NONE
				, NULL
				, NULL
				, DISPMANX_NO_ROTATE
				);

			s_dispmanWindow.element = dispmanElement;
			s_dispmanWindow.width   = _width;
			s_dispmanWindow.height  = _height;
			nwh = &s_dispmanWindow;

			vc_dispmanx_update_submit_sync(dispmanUpdate);
#	endif // BX_PLATFORM_ANDROID

			m_surface = eglCreateWindowSurface(m_display, m_config, nwh, NULL);
			BGFX_FATAL(m_surface != EGL_NO_SURFACE, Fatal::UnableToInitialize, "Failed to create surface.");

			const bool hasEglKhrCreateContext = !!bx::findIdentifierMatch(extensions, "EGL_KHR_create_context");
			const bool hasEglKhrNoError       = !!bx::findIdentifierMatch(extensions, "EGL_KHR_create_context_no_error");

			const uint32_t gles = BGFX_CONFIG_RENDERER_OPENGLES;

			for (uint32_t ii = 0; ii < 2; ++ii)
			{
				bx::StaticMemoryBlockWriter writer(s_contextAttrs, sizeof(s_contextAttrs) );

				EGLint flags = 0;

#	if BX_PLATFORM_RPI
				BX_UNUSED(hasEglKhrCreateContext, hasEglKhrNoError);
#	else
				if (hasEglKhrCreateContext)
				{
					bx::write(&writer, EGLint(EGL_CONTEXT_MAJOR_VERSION_KHR) );
					bx::write(&writer, EGLint(gles / 10) );

					bx::write(&writer, EGLint(EGL_CONTEXT_MINOR_VERSION_KHR) );
					bx::write(&writer, EGLint(gles % 10) );

					flags |= BGFX_CONFIG_DEBUG && hasEglKhrNoError ? 0
						| EGL_CONTEXT_FLAG_NO_ERROR_BIT_KHR
						: 0
						;

					if (0 == ii)
					{
						flags |= BGFX_CONFIG_DEBUG ? 0
							| EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
//							| EGL_OPENGL_ES3_BIT_KHR
							: 0
							;

						bx::write(&writer, EGLint(EGL_CONTEXT_FLAGS_KHR) );
						bx::write(&writer, flags);
					}
				}
				else
#	endif // BX_PLATFORM_RPI
				{
					bx::write(&writer, EGLint(EGL_CONTEXT_CLIENT_VERSION) );
					bx::write(&writer, 2);
				}

				bx::write(&writer, EGLint(EGL_NONE) );

				m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, s_contextAttrs);
				if (NULL != m_context)
				{
					break;
				}

				BX_TRACE("Failed to create EGL context with EGL_CONTEXT_FLAGS_KHR (%08x).", flags);
			}

			BGFX_FATAL(m_context != EGL_NO_CONTEXT, Fatal::UnableToInitialize, "Failed to create context.");

			success = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
			BGFX_FATAL(success, Fatal::UnableToInitialize, "Failed to set context.");
			m_current = NULL;

			eglSwapInterval(m_display, 0);
		}

		import();

		g_internalData.context = m_context;
	}
Beispiel #16
0
	bool OVR::postReset(void* _nwh, ovrRenderAPIConfig* _config, bool _debug)
	{
		if (_debug)
		{
			switch (_config->Header.API)
			{
#if BGFX_CONFIG_RENDERER_DIRECT3D11
			case ovrRenderAPI_D3D11:
				{
					ovrD3D11ConfigData* data = (ovrD3D11ConfigData*)_config;
#	if OVR_VERSION > OVR_VERSION_043
					m_rtSize = data->Header.BackBufferSize;
#	else
					m_rtSize = data->Header.RTSize;
#	endif // OVR_VERSION > OVR_VERSION_043
				}
				break;
#endif // BGFX_CONFIG_RENDERER_DIRECT3D11

#if BGFX_CONFIG_RENDERER_OPENGL
			case ovrRenderAPI_OpenGL:
				{
					ovrGLConfigData* data = (ovrGLConfigData*)_config;
#	if OVR_VERSION > OVR_VERSION_043
					m_rtSize = data->Header.BackBufferSize;
#	else
					m_rtSize = data->Header.RTSize;
#	endif // OVR_VERSION > OVR_VERSION_043
				}
				break;
#endif // BGFX_CONFIG_RENDERER_OPENGL

			case ovrRenderAPI_None:
			default:
				BX_CHECK(false, "You should not be here!");
				break;
			}

			m_debug = true;
			return false;
		}

		if (!m_initialized)
		{
			return false;
		}

		if (!_debug)
		{
			m_hmd = ovrHmd_Create(0);
		}

		if (NULL == m_hmd)
		{
			m_hmd = ovrHmd_CreateDebug(ovrHmd_DK2);
			BX_WARN(NULL != m_hmd, "Unable to initialize OVR.");

			if (NULL == m_hmd)
			{
				return false;
			}
		}

		BX_TRACE("HMD: %s, %s, firmware: %d.%d"
			, m_hmd->ProductName
			, m_hmd->Manufacturer
			, m_hmd->FirmwareMajor
			, m_hmd->FirmwareMinor
			);

		ovrBool result;
		result = ovrHmd_AttachToWindow(m_hmd, _nwh, NULL, NULL);
		if (!result) { goto ovrError; }

		ovrFovPort eyeFov[2] = { m_hmd->DefaultEyeFov[0], m_hmd->DefaultEyeFov[1] };
		result = ovrHmd_ConfigureRendering(m_hmd
			, _config
			, 0
#if OVR_VERSION < OVR_VERSION_050
			| ovrDistortionCap_Chromatic // permanently enabled >= v5.0
#endif
			| ovrDistortionCap_Vignette
			| ovrDistortionCap_TimeWarp
			| ovrDistortionCap_Overdrive
			| ovrDistortionCap_NoRestore
			| ovrDistortionCap_HqDistortion
			, eyeFov
			, m_erd
			);
		if (!result) { goto ovrError; }

		ovrHmd_SetEnabledCaps(m_hmd
			, 0
			| ovrHmdCap_LowPersistence
			| ovrHmdCap_DynamicPrediction
			);

		result = ovrHmd_ConfigureTracking(m_hmd
			, 0
			| ovrTrackingCap_Orientation
			| ovrTrackingCap_MagYawCorrection
			| ovrTrackingCap_Position
			, 0
			);

		if (!result)
		{
ovrError:
			BX_TRACE("Failed to initialize OVR.");
			ovrHmd_Destroy(m_hmd);
			m_hmd = NULL;
			return false;
		}

		ovrSizei sizeL = ovrHmd_GetFovTextureSize(m_hmd, ovrEye_Left,  m_hmd->DefaultEyeFov[0], 1.0f);
		ovrSizei sizeR = ovrHmd_GetFovTextureSize(m_hmd, ovrEye_Right, m_hmd->DefaultEyeFov[1], 1.0f);
		m_rtSize.w = sizeL.w + sizeR.w;
		m_rtSize.h = bx::uint32_max(sizeL.h, sizeR.h);

		m_warning = true;

		return true;
	}
bool getReflectionDataD3D11(ID3DBlob* _code, bool _vshader, UniformArray& _uniforms, uint8_t& _numAttrs, uint16_t* _attrs, uint16_t& _size, UniformNameList& unusedUniforms)
{
    ID3D11ShaderReflection* reflect = NULL;
    HRESULT hr = D3DReflect(_code->GetBufferPointer()
                            , _code->GetBufferSize()
                            , s_compiler->IID_ID3D11ShaderReflection
                            , (void**)&reflect
                           );
    if (FAILED(hr) )
    {
        fprintf(stderr, "Error: D3DReflect failed 0x%08x\n", (uint32_t)hr);
        return false;
    }

    D3D11_SHADER_DESC desc;
    hr = reflect->GetDesc(&desc);
    if (FAILED(hr) )
    {
        fprintf(stderr, "Error: ID3D11ShaderReflection::GetDesc failed 0x%08x\n", (uint32_t)hr);
        return false;
    }

    BX_TRACE("Creator: %s 0x%08x", desc.Creator, desc.Version);
    BX_TRACE("Num constant buffers: %d", desc.ConstantBuffers);

    BX_TRACE("Input:");

    if (_vshader) // Only care about input semantic on vertex shaders
    {
        for (uint32_t ii = 0; ii < desc.InputParameters; ++ii)
        {
            D3D11_SIGNATURE_PARAMETER_DESC spd;
            reflect->GetInputParameterDesc(ii, &spd);
            BX_TRACE("\t%2d: %s%d, vt %d, ct %d, mask %x, reg %d"
                     , ii
                     , spd.SemanticName
                     , spd.SemanticIndex
                     , spd.SystemValueType
                     , spd.ComponentType
                     , spd.Mask
                     , spd.Register
                    );

            const RemapInputSemantic& ris = findInputSemantic(spd.SemanticName, spd.SemanticIndex);
            if (ris.m_attr != bgfx::Attrib::Count)
            {
                _attrs[_numAttrs] = bgfx::attribToId(ris.m_attr);
                ++_numAttrs;
            }
        }
    }

    BX_TRACE("Output:");
    for (uint32_t ii = 0; ii < desc.OutputParameters; ++ii)
    {
        D3D11_SIGNATURE_PARAMETER_DESC spd;
        reflect->GetOutputParameterDesc(ii, &spd);
        BX_TRACE("\t%2d: %s%d, %d, %d", ii, spd.SemanticName, spd.SemanticIndex, spd.SystemValueType, spd.ComponentType);
    }

    for (uint32_t ii = 0, num = bx::uint32_min(1, desc.ConstantBuffers); ii < num; ++ii)
    {
        ID3D11ShaderReflectionConstantBuffer* cbuffer = reflect->GetConstantBufferByIndex(ii);
        D3D11_SHADER_BUFFER_DESC bufferDesc;
        hr = cbuffer->GetDesc(&bufferDesc);

        _size = (uint16_t)bufferDesc.Size;

        if (SUCCEEDED(hr) )
        {
            BX_TRACE("%s, %d, vars %d, size %d"
                     , bufferDesc.Name
                     , bufferDesc.Type
                     , bufferDesc.Variables
                     , bufferDesc.Size
                    );

            for (uint32_t jj = 0; jj < bufferDesc.Variables; ++jj)
            {
                ID3D11ShaderReflectionVariable* var = cbuffer->GetVariableByIndex(jj);
                ID3D11ShaderReflectionType* type = var->GetType();
                D3D11_SHADER_VARIABLE_DESC varDesc;
                hr = var->GetDesc(&varDesc);
                if (SUCCEEDED(hr) )
                {
                    D3D11_SHADER_TYPE_DESC constDesc;
                    hr = type->GetDesc(&constDesc);
                    if (SUCCEEDED(hr) )
                    {
                        UniformType::Enum uniformType = findUniformType(constDesc);

                        if (UniformType::Count != uniformType
                                &&  0 != (varDesc.uFlags & D3D_SVF_USED) )
                        {
                            Uniform un;
                            un.name = varDesc.Name;
                            un.type = uniformType;
                            un.num = constDesc.Elements;
                            un.regIndex = varDesc.StartOffset;
                            un.regCount = BX_ALIGN_16(varDesc.Size) / 16;
                            _uniforms.push_back(un);

                            BX_TRACE("\t%s, %d, size %d, flags 0x%08x, %d (used)"
                                     , varDesc.Name
                                     , varDesc.StartOffset
                                     , varDesc.Size
                                     , varDesc.uFlags
                                     , uniformType
                                    );
                        }
                        else
                        {
                            if (0 == (varDesc.uFlags & D3D_SVF_USED) )
                            {
                                unusedUniforms.push_back(varDesc.Name);
                            }

                            BX_TRACE("\t%s, unknown type", varDesc.Name);
                        }
                    }
                }
            }
        }
    }

    BX_TRACE("Bound:");
    for (uint32_t ii = 0; ii < desc.BoundResources; ++ii)
    {
        D3D11_SHADER_INPUT_BIND_DESC bindDesc;

        hr = reflect->GetResourceBindingDesc(ii, &bindDesc);
        if (SUCCEEDED(hr) )
        {
            if (D3D_SIT_SAMPLER == bindDesc.Type)
            {
                BX_TRACE("\t%s, %d, %d, %d"
                         , bindDesc.Name
                         , bindDesc.Type
                         , bindDesc.BindPoint
                         , bindDesc.BindCount
                        );

                const char * end = strstr(bindDesc.Name, "Sampler");
                if (NULL != end)
                {
                    Uniform un;
                    un.name.assign(bindDesc.Name, (end - bindDesc.Name) );
                    un.type = UniformType::Enum(BGFX_UNIFORM_SAMPLERBIT | UniformType::Int1);
                    un.num = 1;
                    un.regIndex = bindDesc.BindPoint;
                    un.regCount = bindDesc.BindCount;
                    _uniforms.push_back(un);
                }
            }
        }
    }

    if (NULL != reflect)
    {
        reflect->Release();
    }

    return true;
}
Beispiel #18
0
bool compileHLSLShaderDx9(bx::CommandLine& _cmdLine, const std::string& _code, bx::WriterI* _writer)
{
	BX_TRACE("DX9");

	const char* profile = _cmdLine.findOption('p', "profile");
	if (NULL == profile)
	{
		fprintf(stderr, "Shader profile must be specified.\n");
		return false;
	}

	bool debug = _cmdLine.hasArg('\0', "debug");

	uint32_t flags = 0;
	flags |= debug ? D3DXSHADER_DEBUG : 0;
	flags |= _cmdLine.hasArg('\0', "avoid-flow-control") ? D3DXSHADER_AVOID_FLOW_CONTROL : 0;
	flags |= _cmdLine.hasArg('\0', "no-preshader") ? D3DXSHADER_NO_PRESHADER : 0;
	flags |= _cmdLine.hasArg('\0', "partial-precision") ? D3DXSHADER_PARTIALPRECISION : 0;
	flags |= _cmdLine.hasArg('\0', "prefer-flow-control") ? D3DXSHADER_PREFER_FLOW_CONTROL : 0;
	flags |= _cmdLine.hasArg('\0', "backwards-compatibility") ? D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY : 0;

	bool werror = _cmdLine.hasArg('\0', "Werror");

	uint32_t optimization = 3;
	if (_cmdLine.hasArg(optimization, 'O') )
	{
		optimization = bx::uint32_min(optimization, BX_COUNTOF(s_optimizationLevelDx9)-1);
		flags |= s_optimizationLevelDx9[optimization];
	}
	else
	{
		flags |= D3DXSHADER_SKIPOPTIMIZATION;
	}

	BX_TRACE("Profile: %s", profile);
	BX_TRACE("Flags: 0x%08x", flags);

	LPD3DXBUFFER code;
	LPD3DXBUFFER errorMsg;
	LPD3DXCONSTANTTABLE constantTable;

	HRESULT hr;

	// Output preprocessed shader so that HLSL can be debugged via GPA
	// or PIX. Compiling through memory won't embed preprocessed shader
	// file path.
	if (debug)
	{
		std::string hlslfp = _cmdLine.findOption('o');
		hlslfp += ".hlsl";
		writeFile(hlslfp.c_str(), _code.c_str(), (int32_t)_code.size() );

		hr = D3DXCompileShaderFromFileA(hlslfp.c_str()
			, NULL
			, NULL
			, "main"
			, profile
			, flags
			, &code
			, &errorMsg
			, &constantTable
			);
	}
	else
	{
		hr = D3DXCompileShader(_code.c_str()
			, (uint32_t)_code.size()
			, NULL
			, NULL
			, "main"
			, profile
			, flags
			, &code
			, &errorMsg
			, &constantTable
			);
	}

	if (FAILED(hr)
	|| (werror && NULL != errorMsg) )
	{
		const char* log = (const char*)errorMsg->GetBufferPointer();

		char source[1024];
		int32_t line = 0;
		int32_t column = 0;
		int32_t start = 0;
		int32_t end = INT32_MAX;

		if (3 == sscanf(log, "%[^(](%u,%u):", source, &line, &column)
		&&  0 != line)
		{
			start = bx::uint32_imax(1, line-10);
			end = start + 20;
		}

		printCode(_code.c_str(), line, start, end);
		fprintf(stderr, "Error: 0x%08x %s\n", (uint32_t)hr, log);
		errorMsg->Release();
		return false;
	}

	UniformArray uniforms;

	if (NULL != constantTable)
	{
		D3DXCONSTANTTABLE_DESC desc;
		hr = constantTable->GetDesc(&desc);
		if (FAILED(hr) )
		{
			fprintf(stderr, "Error 0x%08x\n", (uint32_t)hr);
			return false;
		}

		BX_TRACE("Creator: %s 0x%08x", desc.Creator, (uint32_t /*mingw warning*/)desc.Version);
		BX_TRACE("Num constants: %d", desc.Constants);
		BX_TRACE("#   cl ty RxC   S  By Name");

		for (uint32_t ii = 0; ii < desc.Constants; ++ii)
		{
			D3DXHANDLE handle = constantTable->GetConstant(NULL, ii);
			D3DXCONSTANT_DESC constDesc;
			uint32_t count;
			constantTable->GetConstantDesc(handle, &constDesc, &count);
			BX_TRACE("%3d %2d %2d [%dx%d] %d %3d %s[%d] c%d (%d)"
				, ii
				, constDesc.Class
				, constDesc.Type
				, constDesc.Rows
				, constDesc.Columns
				, constDesc.StructMembers
				, constDesc.Bytes
				, constDesc.Name
				, constDesc.Elements
				, constDesc.RegisterIndex
				, constDesc.RegisterCount
				);

			UniformType::Enum type = findUniformTypeDx9(constDesc);
			if (UniformType::Count != type)
			{
				Uniform un;
				un.name = '$' == constDesc.Name[0] ? constDesc.Name+1 : constDesc.Name;
				un.type = type;
				un.num = constDesc.Elements;
				un.regIndex = constDesc.RegisterIndex;
				un.regCount = constDesc.RegisterCount;
				uniforms.push_back(un);
			}
		}
	}

	uint16_t count = (uint16_t)uniforms.size();
	bx::write(_writer, count);

	uint32_t fragmentBit = profile[0] == 'p' ? BGFX_UNIFORM_FRAGMENTBIT : 0;
	for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
	{
		const Uniform& un = *it;
		uint8_t nameSize = (uint8_t)un.name.size();
		bx::write(_writer, nameSize);
		bx::write(_writer, un.name.c_str(), nameSize);
		uint8_t type = un.type|fragmentBit;
		bx::write(_writer, type);
		bx::write(_writer, un.num);
		bx::write(_writer, un.regIndex);
		bx::write(_writer, un.regCount);

		BX_TRACE("%s, %s, %d, %d, %d"
			, un.name.c_str()
			, getUniformTypeName(un.type)
			, un.num
			, un.regIndex
			, un.regCount
			);
	}

	uint16_t shaderSize = (uint16_t)code->GetBufferSize();
	bx::write(_writer, shaderSize);
	bx::write(_writer, code->GetBufferPointer(), shaderSize);
	uint8_t nul = 0;
	bx::write(_writer, nul);

	if (_cmdLine.hasArg('\0', "disasm") )
	{
		LPD3DXBUFFER disasm;
		D3DXDisassembleShader( (const DWORD*)code->GetBufferPointer()
			, false
			, NULL
			, &disasm
			);

		if (NULL != disasm)
		{
			std::string disasmfp = _cmdLine.findOption('o');
			disasmfp += ".disasm";

			writeFile(disasmfp.c_str(), disasm->GetBufferPointer(), disasm->GetBufferSize() );
			disasm->Release();
		}
	}

	if (NULL != code)
	{
		code->Release();
	}

	if (NULL != errorMsg)
	{
		errorMsg->Release();
	}

	if (NULL != constantTable)
	{
		constantTable->Release();
	}

	return true;
}
Beispiel #19
0
	void GlContext::create(uint32_t /*_width*/, uint32_t /*_height*/)
	{
		m_opengl32dll = bx::dlopen("opengl32.dll");
		BGFX_FATAL(NULL != m_opengl32dll, Fatal::UnableToInitialize, "Failed to load opengl32.dll.");

		wglGetProcAddress = (PFNWGLGETPROCADDRESSPROC)bx::dlsym(m_opengl32dll, "wglGetProcAddress");
		BGFX_FATAL(NULL != wglGetProcAddress, Fatal::UnableToInitialize, "Failed get wglGetProcAddress.");

		// If g_bgfxHwnd is NULL, the assumption is that GL context was created
		// by user (for example, using SDL, GLFW, etc.)
		BX_WARN(NULL != g_bgfxHwnd
			, "bgfx::winSetHwnd with valid window is not called. This might "
			  "be intentional when GL context is created by the user."
			);

		if (NULL != g_bgfxHwnd)
		{
			wglMakeCurrent = (PFNWGLMAKECURRENTPROC)bx::dlsym(m_opengl32dll, "wglMakeCurrent");
			BGFX_FATAL(NULL != wglMakeCurrent, Fatal::UnableToInitialize, "Failed get wglMakeCurrent.");

			wglCreateContext = (PFNWGLCREATECONTEXTPROC)bx::dlsym(m_opengl32dll, "wglCreateContext");
			BGFX_FATAL(NULL != wglCreateContext, Fatal::UnableToInitialize, "Failed get wglCreateContext.");

			wglDeleteContext = (PFNWGLDELETECONTEXTPROC)bx::dlsym(m_opengl32dll, "wglDeleteContext");
			BGFX_FATAL(NULL != wglDeleteContext, Fatal::UnableToInitialize, "Failed get wglDeleteContext.");

			m_hdc = GetDC(g_bgfxHwnd);
			BGFX_FATAL(NULL != m_hdc, Fatal::UnableToInitialize, "GetDC failed!");

			// Dummy window to peek into WGL functionality.
			//
			// An application can only set the pixel format of a window one time.
			// Once a window's pixel format is set, it cannot be changed.
			// MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd369049%28v=vs.85%29.aspx
			HWND hwnd = CreateWindowA("STATIC"
				, ""
				, WS_POPUP|WS_DISABLED
				, -32000
				, -32000
				, 0
				, 0
				, NULL
				, NULL
				, GetModuleHandle(NULL)
				, 0
				);

			HDC hdc = GetDC(hwnd);
			BGFX_FATAL(NULL != hdc, Fatal::UnableToInitialize, "GetDC failed!");

			HGLRC context = createContext(hdc);

			wglGetExtensionsStringARB  = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
			wglChoosePixelFormatARB    = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
			wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
			wglSwapIntervalEXT         = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");

			if (NULL != wglGetExtensionsStringARB)
			{
				const char* extensions = (const char*)wglGetExtensionsStringARB(hdc);
				BX_TRACE("WGL extensions:");
				dumpExtensions(extensions);
			}

			if (NULL != wglChoosePixelFormatARB
			&&  NULL != wglCreateContextAttribsARB)
			{
				int32_t attrs[] =
				{
					WGL_SAMPLE_BUFFERS_ARB, 0,
					WGL_SAMPLES_ARB, 0,
					WGL_SUPPORT_OPENGL_ARB, true,
					WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
					WGL_DRAW_TO_WINDOW_ARB, true,
					WGL_DOUBLE_BUFFER_ARB, true,
					WGL_COLOR_BITS_ARB, 32,
					WGL_DEPTH_BITS_ARB, 24,
					WGL_STENCIL_BITS_ARB, 8,
					0
				};

				int result;
				uint32_t numFormats = 0;
				do 
				{
					result = wglChoosePixelFormatARB(m_hdc, attrs, NULL, 1, &m_pixelFormat, &numFormats);
					if (0 == result
						||  0 == numFormats)
					{
						attrs[3] >>= 1;
						attrs[1] = attrs[3] == 0 ? 0 : 1;
					}

				} while (0 == numFormats);

				DescribePixelFormat(m_hdc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_pfd);

				BX_TRACE("Pixel format:\n"
					"\tiPixelType %d\n"
					"\tcColorBits %d\n"
					"\tcAlphaBits %d\n"
					"\tcDepthBits %d\n"
					"\tcStencilBits %d\n"
					, m_pfd.iPixelType
					, m_pfd.cColorBits
					, m_pfd.cAlphaBits
					, m_pfd.cDepthBits
					, m_pfd.cStencilBits
					);

				result = SetPixelFormat(m_hdc, m_pixelFormat, &m_pfd);
				// When window is created by SDL and SDL_WINDOW_OPENGL is set SetPixelFormat
				// will fail. Just warn and continue. In case it failed for some other reason
				// create context will fail and it will error out there.
				BX_WARN(result, "SetPixelFormat failed (last err: 0x%08x)!", GetLastError() );

				uint32_t flags = BGFX_CONFIG_DEBUG ? WGL_CONTEXT_DEBUG_BIT_ARB : 0;
				BX_UNUSED(flags);
				int32_t contextAttrs[9] =
				{
#if BGFX_CONFIG_RENDERER_OPENGL >= 31
					WGL_CONTEXT_MAJOR_VERSION_ARB, BGFX_CONFIG_RENDERER_OPENGL / 10,
					WGL_CONTEXT_MINOR_VERSION_ARB, BGFX_CONFIG_RENDERER_OPENGL % 10,
					WGL_CONTEXT_FLAGS_ARB, flags,
					WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
#else
					WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
					WGL_CONTEXT_MINOR_VERSION_ARB, 1,
					0, 0,
					0, 0,
#endif // BGFX_CONFIG_RENDERER_OPENGL >= 31
					0
				};

				m_context = wglCreateContextAttribsARB(m_hdc, 0, contextAttrs);
				if (NULL == m_context)
				{
					// nVidia doesn't like context profile mask for contexts below 3.2?
					contextAttrs[6] = WGL_CONTEXT_PROFILE_MASK_ARB == contextAttrs[6] ? 0 : contextAttrs[6];
					m_context = wglCreateContextAttribsARB(m_hdc, 0, contextAttrs);
				}
				BGFX_FATAL(NULL != m_context, Fatal::UnableToInitialize, "Failed to create context 0x%08x.", GetLastError() );

				BX_STATIC_ASSERT(sizeof(contextAttrs) == sizeof(m_contextAttrs) );
				memcpy(m_contextAttrs, contextAttrs, sizeof(contextAttrs) );
			}
Beispiel #20
0
	static bool compile(bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer, bool _firstPass)
	{
		const char* profile = _cmdLine.findOption('p', "profile");
		if (NULL == profile)
		{
			fprintf(stderr, "Error: Shader profile must be specified.\n");
			return false;
		}

		s_compiler = load();

		bool result = false;
		bool debug = _cmdLine.hasArg('\0', "debug");

		uint32_t flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;
		flags |= debug ? D3DCOMPILE_DEBUG : 0;
		flags |= _cmdLine.hasArg('\0', "avoid-flow-control") ? D3DCOMPILE_AVOID_FLOW_CONTROL : 0;
		flags |= _cmdLine.hasArg('\0', "no-preshader") ? D3DCOMPILE_NO_PRESHADER : 0;
		flags |= _cmdLine.hasArg('\0', "partial-precision") ? D3DCOMPILE_PARTIAL_PRECISION : 0;
		flags |= _cmdLine.hasArg('\0', "prefer-flow-control") ? D3DCOMPILE_PREFER_FLOW_CONTROL : 0;
		flags |= _cmdLine.hasArg('\0', "backwards-compatibility") ? D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY : 0;

		bool werror = _cmdLine.hasArg('\0', "Werror");

		if (werror)
		{
			flags |= D3DCOMPILE_WARNINGS_ARE_ERRORS;
		}

		uint32_t optimization = 3;
		if (_cmdLine.hasArg(optimization, 'O') )
		{
			optimization = bx::uint32_min(optimization, BX_COUNTOF(s_optimizationLevelD3D11) - 1);
			flags |= s_optimizationLevelD3D11[optimization];
		}
		else
		{
			flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
		}

		BX_TRACE("Profile: %s", profile);
		BX_TRACE("Flags: 0x%08x", flags);

		ID3DBlob* code;
		ID3DBlob* errorMsg;

		// Output preprocessed shader so that HLSL can be debugged via GPA
		// or PIX. Compiling through memory won't embed preprocessed shader
		// file path.
		std::string hlslfp;

		if (debug)
		{
			hlslfp = _cmdLine.findOption('o');
			hlslfp += ".hlsl";
			writeFile(hlslfp.c_str(), _code.c_str(), (int32_t)_code.size() );
		}

		HRESULT hr = D3DCompile(_code.c_str()
			, _code.size()
			, hlslfp.c_str()
			, NULL
			, NULL
			, "main"
			, profile
			, flags
			, 0
			, &code
			, &errorMsg
			);
		if (FAILED(hr)
		|| (werror && NULL != errorMsg) )
		{
			const char* log = (char*)errorMsg->GetBufferPointer();

			int32_t line   = 0;
			int32_t column = 0;
			int32_t start  = 0;
			int32_t end    = INT32_MAX;

			bool found = false
				|| 2 == sscanf(log, "(%u,%u):", &line, &column)
				|| 2 == sscanf(log, " :%u:%u: ", &line, &column)
				;

			if (found
			&&  0 != line)
			{
				start = bx::uint32_imax(1, line - 10);
				end   = start + 20;
			}

			printCode(_code.c_str(), line, start, end, column);
			fprintf(stderr, "Error: D3DCompile failed 0x%08x %s\n", (uint32_t)hr, log);
			errorMsg->Release();
			return false;
		}

		UniformArray uniforms;
		uint8_t numAttrs = 0;
		uint16_t attrs[bgfx::Attrib::Count];
		uint16_t size = 0;

		if (_version == 9)
		{
			if (!getReflectionDataD3D9(code, uniforms) )
			{
				fprintf(stderr, "Error: Unable to get D3D9 reflection data.\n");
				goto error;
			}
		}
		else
		{
			UniformNameList unusedUniforms;
			if (!getReflectionDataD3D11(code, profile[0] == 'v', uniforms, numAttrs, attrs, size, unusedUniforms) )
			{
				fprintf(stderr, "Error: Unable to get D3D11 reflection data.\n");
				goto error;
			}

			if (_firstPass
			&&  unusedUniforms.size() > 0)
			{
				const size_t strLength = strlen("uniform");

				// first time through, we just find unused uniforms and get rid of them
				std::string output;
				LineReader reader(_code.c_str() );
				while (!reader.isEof() )
				{
					std::string line = reader.getLine();
					for (UniformNameList::iterator it = unusedUniforms.begin(), itEnd = unusedUniforms.end(); it != itEnd; ++it)
					{
						size_t index = line.find("uniform ");
						if (index == std::string::npos)
						{
							continue;
						}

						// matching lines like:  uniform u_name;
						// we want to replace "uniform" with "static" so that it's no longer
						// included in the uniform blob that the application must upload
						// we can't just remove them, because unused functions might still reference
						// them and cause a compile error when they're gone
						if (!!bx::findIdentifierMatch(line.c_str(), it->c_str() ) )
						{
							line = line.replace(index, strLength, "static");
							unusedUniforms.erase(it);
							break;
						}
					}

					output += line;
				}

				// recompile with the unused uniforms converted to statics
				return compile(_cmdLine, _version, output.c_str(), _writer, false);
			}
		}

		{
			uint16_t count = (uint16_t)uniforms.size();
			bx::write(_writer, count);

			uint32_t fragmentBit = profile[0] == 'p' ? BGFX_UNIFORM_FRAGMENTBIT : 0;
			for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
			{
				const Uniform& un = *it;
				uint8_t nameSize = (uint8_t)un.name.size();
				bx::write(_writer, nameSize);
				bx::write(_writer, un.name.c_str(), nameSize);
				uint8_t type = uint8_t(un.type | fragmentBit);
				bx::write(_writer, type);
				bx::write(_writer, un.num);
				bx::write(_writer, un.regIndex);
				bx::write(_writer, un.regCount);

				BX_TRACE("%s, %s, %d, %d, %d"
					, un.name.c_str()
					, getUniformTypeName(un.type)
					, un.num
					, un.regIndex
					, un.regCount
					);
			}
		}

		{
			ID3DBlob* stripped;
			hr = D3DStripShader(code->GetBufferPointer()
				, code->GetBufferSize()
				, D3DCOMPILER_STRIP_REFLECTION_DATA
				| D3DCOMPILER_STRIP_TEST_BLOBS
				, &stripped
				);

			if (SUCCEEDED(hr) )
			{
				code->Release();
				code = stripped;
			}
		}

		{
			uint16_t shaderSize = (uint16_t)code->GetBufferSize();
			bx::write(_writer, shaderSize);
			bx::write(_writer, code->GetBufferPointer(), shaderSize);
			uint8_t nul = 0;
			bx::write(_writer, nul);
		}

		if (_version > 9)
		{
			bx::write(_writer, numAttrs);
			bx::write(_writer, attrs, numAttrs*sizeof(uint16_t) );

			bx::write(_writer, size);
		}

		if (_cmdLine.hasArg('\0', "disasm") )
		{
			ID3DBlob* disasm;
			D3DDisassemble(code->GetBufferPointer()
				, code->GetBufferSize()
				, 0
				, NULL
				, &disasm
				);

			if (NULL != disasm)
			{
				std::string disasmfp = _cmdLine.findOption('o');
				disasmfp += ".disasm";

				writeFile(disasmfp.c_str(), disasm->GetBufferPointer(), (uint32_t)disasm->GetBufferSize() );
				disasm->Release();
			}
		}

		if (NULL != errorMsg)
		{
			errorMsg->Release();
		}

		result = true;

	error:
		code->Release();
		unload();
		return result;
	}
Beispiel #21
0
	void VRImplOVR::connect(VRDesc* _desc)
	{
		ovrGraphicsLuid luid;
		ovrResult result = ovr_Create(&m_session, &luid);
		if (!OVR_SUCCESS(result))
		{
			BX_TRACE("Failed to create OVR device.");
			return;
		}

		BX_STATIC_ASSERT(sizeof(_desc->m_adapterLuid) >= sizeof(luid));
		memcpy(&_desc->m_adapterLuid, &luid, sizeof(luid));

		ovrHmdDesc hmdDesc = ovr_GetHmdDesc(m_session);
		_desc->m_deviceType = hmdDesc.Type;
		_desc->m_refreshRate = hmdDesc.DisplayRefreshRate;
		_desc->m_deviceSize.m_w = hmdDesc.Resolution.w;
		_desc->m_deviceSize.m_h = hmdDesc.Resolution.h;

		BX_TRACE("OVR HMD: %s, %s, firmware: %d.%d"
			, hmdDesc.ProductName
			, hmdDesc.Manufacturer
			, hmdDesc.FirmwareMajor
			, hmdDesc.FirmwareMinor
			);

		ovrSizei eyeSize[2] =
		{
			ovr_GetFovTextureSize(m_session, ovrEye_Left, hmdDesc.DefaultEyeFov[0], 1.0f),
			ovr_GetFovTextureSize(m_session, ovrEye_Right, hmdDesc.DefaultEyeFov[0], 1.0f),
		};

		for (int eye = 0; eye < 2; ++eye)
		{
			BX_STATIC_ASSERT(sizeof(_desc->m_eyeFov[eye]) == sizeof(hmdDesc.DefaultEyeFov[eye]));
			memcpy(&_desc->m_eyeFov[eye], &hmdDesc.DefaultEyeFov[eye], sizeof(_desc->m_eyeFov[eye]));
			_desc->m_eyeSize[eye].m_w = eyeSize[eye].w;
			_desc->m_eyeSize[eye].m_h = eyeSize[eye].h;
		}

		float neckOffset[2] = {OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL, OVR_DEFAULT_NECK_TO_EYE_VERTICAL};
		ovr_GetFloatArray(m_session, OVR_KEY_NECK_TO_EYE_DISTANCE, neckOffset, 2);
		_desc->m_neckOffset[0] = neckOffset[0];
		_desc->m_neckOffset[1] = neckOffset[1];

		// build constant layer settings
		m_renderLayer.Header.Type = ovrLayerType_EyeFov;
		m_renderLayer.Header.Flags = 0;
		for (int eye = 0; eye < 2; ++eye)
		{
			m_renderLayer.Fov[eye] = hmdDesc.DefaultEyeFov[eye];
			m_renderLayer.Viewport[eye].Pos.x = 0;
			m_renderLayer.Viewport[eye].Pos.y = 0;
			m_renderLayer.Viewport[eye].Size = eyeSize[eye];
		}

		m_viewScale.HmdSpaceToWorldScaleInMeters = 1.0f;
		for (int eye = 0; eye < 2; ++eye)
		{
			ovrEyeRenderDesc erd = ovr_GetRenderDesc(m_session, static_cast<ovrEyeType>(eye), hmdDesc.DefaultEyeFov[eye]);
			m_viewScale.HmdToEyeOffset[eye] = erd.HmdToEyeOffset;
			m_eyeFov[eye] = erd.Fov;
			m_pixelsPerTanAngleAtCenter[eye] = erd.PixelsPerTanAngleAtCenter;
		}
	}
Beispiel #22
0
bool compileHLSLShaderDx11(bx::CommandLine& _cmdLine, const std::string& _code, bx::WriterI* _writer)
{
	BX_TRACE("DX11");

	const char* profile = _cmdLine.findOption('p', "profile");
	if (NULL == profile)
	{
		fprintf(stderr, "Shader profile must be specified.\n");
		return false;
	}

	bool debug = _cmdLine.hasArg('\0', "debug");

	uint32_t flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;
	flags |= debug ? D3DCOMPILE_DEBUG : 0;
	flags |= _cmdLine.hasArg('\0', "avoid-flow-control") ? D3DCOMPILE_AVOID_FLOW_CONTROL : 0;
	flags |= _cmdLine.hasArg('\0', "no-preshader") ? D3DCOMPILE_NO_PRESHADER : 0;
	flags |= _cmdLine.hasArg('\0', "partial-precision") ? D3DCOMPILE_PARTIAL_PRECISION : 0;
	flags |= _cmdLine.hasArg('\0', "prefer-flow-control") ? D3DCOMPILE_PREFER_FLOW_CONTROL : 0;
	flags |= _cmdLine.hasArg('\0', "backwards-compatibility") ? D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY : 0;

	bool werror = _cmdLine.hasArg('\0', "Werror");

	if (werror)
	{
		flags |= D3DCOMPILE_WARNINGS_ARE_ERRORS;
	}

	uint32_t optimization = 3;
	if (_cmdLine.hasArg(optimization, 'O') )
	{
		optimization = bx::uint32_min(optimization, BX_COUNTOF(s_optimizationLevelDx11)-1);
		flags |= s_optimizationLevelDx11[optimization];
	}
	else
	{
		flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
	}

	BX_TRACE("Profile: %s", profile);
	BX_TRACE("Flags: 0x%08x", flags);

	ID3DBlob* code;
	ID3DBlob* errorMsg;

	// Output preprocessed shader so that HLSL can be debugged via GPA
	// or PIX. Compiling through memory won't embed preprocessed shader
	// file path.
	std::string hlslfp;

	if (debug)
	{
		hlslfp = _cmdLine.findOption('o');
		hlslfp += ".hlsl";
		writeFile(hlslfp.c_str(), _code.c_str(), (int32_t)_code.size() );
	}

	HRESULT hr = D3DCompile(_code.c_str()
		, _code.size()
		, hlslfp.c_str()
		, NULL
		, NULL
		, "main"
		, profile
		, flags
		, 0
		, &code
		, &errorMsg
		);
	if (FAILED(hr)
	|| (werror && NULL != errorMsg) )
	{
		const char* log = (char*)errorMsg->GetBufferPointer();

		int32_t line = 0;
		int32_t column = 0;
		int32_t start = 0;
		int32_t end = INT32_MAX;

		if (2 == sscanf(log, "(%u,%u):", &line, &column)
		&&  0 != line)
		{
			start = bx::uint32_imax(1, line-10);
			end = start + 20;
		}

		printCode(_code.c_str(), line, start, end);
		fprintf(stderr, "Error: 0x%08x %s\n", (uint32_t)hr, log);
		errorMsg->Release();
		return false;
	}

	UniformArray uniforms;

	ID3D11ShaderReflection* reflect = NULL;
	hr = D3DReflect(code->GetBufferPointer()
		, code->GetBufferSize()
		, IID_ID3D11ShaderReflection
		, (void**)&reflect
		);
	if (FAILED(hr) )
	{
		fprintf(stderr, "Error: 0x%08x\n", (uint32_t)hr);
		return false;
	}

	D3D11_SHADER_DESC desc;
	hr = reflect->GetDesc(&desc);
	if (FAILED(hr) )
	{
		fprintf(stderr, BX_FILE_LINE_LITERAL "Error: 0x%08x\n", (uint32_t)hr);
		return false;
	}

	BX_TRACE("Creator: %s 0x%08x", desc.Creator, desc.Version);
	BX_TRACE("Num constant buffers: %d", desc.ConstantBuffers);

	BX_TRACE("Input:");
	uint8_t numAttrs = 0;
	uint16_t attrs[bgfx::Attrib::Count];

	if (profile[0] == 'v') // Only care about input semantic on vertex shaders
	{
		for (uint32_t ii = 0; ii < desc.InputParameters; ++ii)
		{
			D3D11_SIGNATURE_PARAMETER_DESC spd;
			reflect->GetInputParameterDesc(ii, &spd);
			BX_TRACE("\t%2d: %s%d, vt %d, ct %d, mask %x, reg %d"
				, ii
				, spd.SemanticName
				, spd.SemanticIndex
				, spd.SystemValueType
				, spd.ComponentType
				, spd.Mask
				, spd.Register
				);

			const RemapInputSemantic& ris = findInputSemantic(spd.SemanticName, spd.SemanticIndex);
			if (ris.m_attr != bgfx::Attrib::Count)
			{
				attrs[numAttrs] = bgfx::attribToId(ris.m_attr);
				++numAttrs;
			}
		}
	}

	BX_TRACE("Output:");
	for (uint32_t ii = 0; ii < desc.OutputParameters; ++ii)
	{
		D3D11_SIGNATURE_PARAMETER_DESC spd;
		reflect->GetOutputParameterDesc(ii, &spd);
		BX_TRACE("\t%2d: %s%d, %d, %d", ii, spd.SemanticName, spd.SemanticIndex, spd.SystemValueType, spd.ComponentType);
	}

	uint16_t size = 0;

	for (uint32_t ii = 0; ii < bx::uint32_min(1, desc.ConstantBuffers); ++ii)
	{
		ID3D11ShaderReflectionConstantBuffer* cbuffer = reflect->GetConstantBufferByIndex(ii);
		D3D11_SHADER_BUFFER_DESC bufferDesc;
		hr = cbuffer->GetDesc(&bufferDesc);

		size = (uint16_t)bufferDesc.Size;

		if (SUCCEEDED(hr) )
		{
			BX_TRACE("%s, %d, vars %d, size %d"
				, bufferDesc.Name
				, bufferDesc.Type
				, bufferDesc.Variables
				, bufferDesc.Size
				);

			for (uint32_t jj = 0; jj < bufferDesc.Variables; ++jj)
			{
				ID3D11ShaderReflectionVariable* var = cbuffer->GetVariableByIndex(jj);
				ID3D11ShaderReflectionType* type = var->GetType();
				D3D11_SHADER_VARIABLE_DESC varDesc;
				hr = var->GetDesc(&varDesc);
				if (SUCCEEDED(hr) )
				{
					D3D11_SHADER_TYPE_DESC constDesc;
					hr = type->GetDesc(&constDesc);
					if (SUCCEEDED(hr) )
					{
						UniformType::Enum uniformType = findUniformTypeDx11(constDesc);

						if (UniformType::Count != uniformType
						&&  0 != (varDesc.uFlags & D3D_SVF_USED) )
						{
							Uniform un;
							un.name = varDesc.Name;
							un.type = uniformType;
							un.num = constDesc.Elements;
							un.regIndex = varDesc.StartOffset;
							un.regCount = BX_ALIGN_16(varDesc.Size)/16;
							uniforms.push_back(un);

							BX_TRACE("\t%s, %d, size %d, flags 0x%08x, %d"
								, varDesc.Name
								, varDesc.StartOffset
								, varDesc.Size
								, varDesc.uFlags
								, uniformType
								);
						}
						else
						{
							BX_TRACE("\t%s, unknown type", varDesc.Name);
						}
					}
				}
			}
		}
	}

	BX_TRACE("Bound:");
	for (uint32_t ii = 0; ii < desc.BoundResources; ++ii)
	{
		D3D11_SHADER_INPUT_BIND_DESC bindDesc;

		hr = reflect->GetResourceBindingDesc(ii, &bindDesc);
		if (SUCCEEDED(hr) )
		{
			//			if (bindDesc.Type == D3D_SIT_SAMPLER)
			{
				BX_TRACE("\t%s, %d, %d, %d"
					, bindDesc.Name
					, bindDesc.Type
					, bindDesc.BindPoint
					, bindDesc.BindCount
					);
			}
		}
	}

	uint16_t count = (uint16_t)uniforms.size();
	bx::write(_writer, count);

	uint32_t fragmentBit = profile[0] == 'p' ? BGFX_UNIFORM_FRAGMENTBIT : 0;
	for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
	{
		const Uniform& un = *it;
		uint8_t nameSize = (uint8_t)un.name.size();
		bx::write(_writer, nameSize);
		bx::write(_writer, un.name.c_str(), nameSize);
		uint8_t type = un.type|fragmentBit;
		bx::write(_writer, type);
		bx::write(_writer, un.num);
		bx::write(_writer, un.regIndex);
		bx::write(_writer, un.regCount);

		BX_TRACE("%s, %s, %d, %d, %d"
			, un.name.c_str()
			, getUniformTypeName(un.type)
			, un.num
			, un.regIndex
			, un.regCount
			);
	}

	{
		ID3DBlob* stripped;
		hr = D3DStripShader(code->GetBufferPointer()
			, code->GetBufferSize()
			, D3DCOMPILER_STRIP_REFLECTION_DATA
			| D3DCOMPILER_STRIP_TEST_BLOBS
			, &stripped
			);

		if (SUCCEEDED(hr) )
		{
			code->Release();
			code = stripped;
		}
	}

	uint16_t shaderSize = (uint16_t)code->GetBufferSize();
	bx::write(_writer, shaderSize);
	bx::write(_writer, code->GetBufferPointer(), shaderSize);
	uint8_t nul = 0;
	bx::write(_writer, nul);

	bx::write(_writer, numAttrs);
	bx::write(_writer, attrs, numAttrs*sizeof(uint16_t) );

	bx::write(_writer, size);

	if (_cmdLine.hasArg('\0', "disasm") )
	{
		ID3DBlob* disasm;
		D3DDisassemble(code->GetBufferPointer()
			, code->GetBufferSize()
			, 0
			, NULL
			, &disasm
			);

		if (NULL != disasm)
		{
			std::string disasmfp = _cmdLine.findOption('o');
			disasmfp += ".disasm";

			writeFile(disasmfp.c_str(), disasm->GetBufferPointer(), (uint32_t)disasm->GetBufferSize() );
			disasm->Release();
		}
	}

	if (NULL != reflect)
	{
		reflect->Release();
	}

	if (NULL != errorMsg)
	{
		errorMsg->Release();
	}

	code->Release();

	return true;
}