Exemple #1
0
	void RecordRegion(const char* id, bool isEnter)
	{
		ENSURE(!m_Frames.empty());
		SFrame& frame = m_Frames.back();

		// Must call glEndQuery before calling glGenQueries (via NewQuery),
		// for compatibility with the GL_EXT_timer_query spec (which says
		// GL_INVALID_OPERATION if a query of any target is active; the ARB
		// spec and OpenGL specs don't appear to say that, but the AMD drivers
		// implement that error (see Trac #1033))

		if (!frame.events.empty())
		{
			pglEndQueryARB(GL_TIME_ELAPSED);
			ogl_WarnIfError();
		}

		SEvent event;
		event.id = id;
		event.query = NewQuery();
		event.isEnter = isEnter;

		pglBeginQueryARB(GL_TIME_ELAPSED, event.query);
		ogl_WarnIfError();

		frame.events.push_back(event);
	}
Exemple #2
0
	bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code)
	{
		ogl_WarnIfError();

		pglBindProgramARB(target, program);

		ogl_WarnIfError();

		pglProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str());

		if (ogl_SquelchError(GL_INVALID_OPERATION))
		{
			GLint errPos = 0;
			glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
			int errLine = std::count(code.begin(), code.begin() + std::min((int)code.length(), errPos + 1), '\n') + 1;
			char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
			LOGERROR(L"Failed to compile %hs program '%ls' (line %d):\n%hs", targetName, file.string().c_str(), errLine, errStr);
			return false;
		}

		pglBindProgramARB(target, 0);

		ogl_WarnIfError();

		return true;
	}
Exemple #3
0
	void FrameEnd()
	{
		RegionLeave("frame");

		pglEndQueryARB(GL_TIME_ELAPSED);
		ogl_WarnIfError();
	}
Exemple #4
0
	void LoadPerfCounters()
	{
		GLuint queryTypeId;
		pglGetFirstPerfQueryIdINTEL(&queryTypeId);
		ogl_WarnIfError();
		do
		{
			char queryName[256];
			GLuint counterBufferSize, numCounters, maxQueries, unknown;
			pglGetPerfQueryInfoINTEL(queryTypeId, ARRAY_SIZE(queryName), queryName, &counterBufferSize, &numCounters, &maxQueries, &unknown);
			ogl_WarnIfError();
			ENSURE(unknown == 1);

			SPerfQueryType query;
			query.queryTypeId = queryTypeId;
			query.name = queryName;
			query.counterBufferSize = counterBufferSize;

			for (GLuint counterId = 1; counterId <= numCounters; ++counterId)
			{
				char counterName[256];
				char counterDesc[2048];
				GLuint counterOffset, counterSize, counterUsage, counterType;
				GLuint64 unknown2;
				pglGetPerfCounterInfoINTEL(queryTypeId, counterId, ARRAY_SIZE(counterName), counterName, ARRAY_SIZE(counterDesc), counterDesc, &counterOffset, &counterSize, &counterUsage, &counterType, &unknown2);
				ogl_WarnIfError();
				ENSURE(unknown2 == 0 || unknown2 == 1);

				SPerfCounter counter;
				counter.name = counterName;
				counter.desc = counterDesc;
				counter.offset = counterOffset;
				counter.size = counterSize;
				counter.type = counterType;
				query.counters.push_back(counter);
			}

			m_QueryTypes.push_back(query);

			pglGetNextPerfQueryIdINTEL(queryTypeId, &queryTypeId);
			ogl_WarnIfError();

		} while (queryTypeId);
	}
Exemple #5
0
	void ProcessFrames()
	{
		while (!m_Frames.empty())
		{
			SFrame& frame = m_Frames.front();

			// Queries become available in order so we only need to check the last one
			GLint available = 0;
			pglGetQueryObjectivARB(frame.events.back().query, GL_QUERY_RESULT_AVAILABLE, &available);
			ogl_WarnIfError();
			if (!available)
				break;

			// The frame's queries are now available, so retrieve and record all their results:

			for (size_t i = 0; i < frame.events.size(); ++i)
			{
				GLuint64 queryTimestamp = 0;
				pglGetQueryObjectui64v(frame.events[i].query, GL_QUERY_RESULT, &queryTimestamp);
					// (use the non-suffixed function here, as defined by GL_ARB_timer_query)
				ogl_WarnIfError();

				// Convert to absolute CPU-clock time
				double t = frame.syncTimeStart + (double)(queryTimestamp - frame.syncTimestampStart) / 1e9;

				// Record a frame-start for syncing
				if (i == 0)
					m_Storage.RecordFrameStart(t);

				if (frame.events[i].isEnter)
					m_Storage.Record(CProfiler2::ITEM_ENTER, t, frame.events[i].id);
				else
					m_Storage.Record(CProfiler2::ITEM_LEAVE, t, frame.events[i].id);

				// Associate the frame number with the "frame" region
				if (i == 0)
					m_Storage.RecordAttributePrintf("%u", frame.num);
			}

			PopFrontFrame();
		}
	}
Exemple #6
0
void ActorViewer::Render()
{
	m.Terrain.MakeDirty(RENDERDATA_UPDATE_COLOR);

	g_Renderer.SetClearColor(m.Background);

	// Set shadows, sky and water locally (avoid clobbering global state)
	bool oldShadows = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
	g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, m.ShadowsEnabled);

	bool oldSky = g_Renderer.GetSkyManager()->m_RenderSky;
	g_Renderer.GetSkyManager()->m_RenderSky = false;

	bool oldWater = g_Renderer.GetWaterManager()->m_RenderWater;
	g_Renderer.GetWaterManager()->m_RenderWater = m.WaterEnabled;

	// Set simulation context for rendering purposes
	g_Renderer.SetSimulation(&m.Simulation2);

	g_Renderer.BeginFrame();

	// Find the centre of the interesting region, in the middle of the patch
	// and half way up the model (assuming there is one)
	CVector3D centre;
	CmpPtr<ICmpVisual> cmpVisual(m.Simulation2, m.Entity);
	if (cmpVisual)
		cmpVisual->GetBounds().GetCentre(centre);
	else
		centre.Y = 0.f;
	centre.X = centre.Z = TERRAIN_TILE_SIZE * m.Terrain.GetPatchesPerSide()*PATCH_SIZE/2;

	CCamera camera = AtlasView::GetView_Actor()->GetCamera();
	camera.m_Orientation.Translate(centre.X, centre.Y, centre.Z);
	camera.UpdateFrustum();

	g_Renderer.SetSceneCamera(camera, camera);

	g_Renderer.RenderScene(m);

	glDisable(GL_DEPTH_TEST);
	g_Logger->Render();
	g_ProfileViewer.RenderProfile();
	glEnable(GL_DEPTH_TEST);

	g_Renderer.EndFrame();

	// Restore the old renderer state
	g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, oldShadows);
	g_Renderer.GetSkyManager()->m_RenderSky = oldSky;
	g_Renderer.GetWaterManager()->m_RenderWater = oldWater;

	ogl_WarnIfError();
}
Exemple #7
0
	~CProfiler2GPU_INTEL_performance_queries()
	{
		// Pop frames to return queries to the free list
		while (!m_Frames.empty())
			PopFrontFrame();

		for (size_t i = 0; i < m_QueryTypes.size(); ++i)
			for (size_t j = 0; j < m_QueryTypes[i].freeQueries.size(); ++j)
				pglDeletePerfQueryINTEL(m_QueryTypes[i].freeQueries[j]);

		ogl_WarnIfError();
	}
Exemple #8
0
	bool Compile(GLhandleARB shader, const VfsPath& file, const CStr& code)
	{
		TIMER_ACCRUE(tc_ShaderGLSLCompile);

		ogl_WarnIfError();

		const char* code_string = code.c_str();
		GLint code_length = code.length();
		pglShaderSourceARB(shader, 1, &code_string, &code_length);

		pglCompileShaderARB(shader);

		GLint ok = 0;
		pglGetShaderiv(shader, GL_COMPILE_STATUS, &ok);

		GLint length = 0;
		pglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);

		// Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0
		// (http://code.google.com/p/android/issues/detail?id=9953)
		if (!ok && length == 0)
			length = 4096;

		if (length > 1)
		{
			char* infolog = new char[length];
			pglGetShaderInfoLog(shader, length, NULL, infolog);

			if (ok)
				LOGMESSAGE(L"Info when compiling shader '%ls':\n%hs", file.string().c_str(), infolog);
			else
				LOGERROR(L"Failed to compile shader '%ls':\n%hs", file.string().c_str(), infolog);

			delete[] infolog;
		}

		ogl_WarnIfError();

		return (ok ? true : false);
	}
Exemple #9
0
	void ProcessFrames()
	{
		while (!m_Frames.empty())
		{
			SFrame& frame = m_Frames.front();

			// Queries become available in order so we only need to check the last one
			GLint available = 0;
			pglGetQueryObjectivARB(frame.events.back().query, GL_QUERY_RESULT_AVAILABLE, &available);
			ogl_WarnIfError();
			if (!available)
				break;

			// The frame's queries are now available, so retrieve and record all their results:

			double t = frame.timeStart;
			m_Storage.RecordFrameStart(t);

			for (size_t i = 0; i < frame.events.size(); ++i)
			{
				if (frame.events[i].isEnter)
					m_Storage.Record(CProfiler2::ITEM_ENTER, t, frame.events[i].id);
				else
					m_Storage.Record(CProfiler2::ITEM_LEAVE, t, frame.events[i].id);

				// Associate the frame number with the "frame" region
				if (i == 0)
					m_Storage.RecordAttributePrintf("%u", frame.num);

				// Advance by the elapsed time to the next event
				GLuint64 queryElapsed = 0;
				pglGetQueryObjectui64vEXT(frame.events[i].query, GL_QUERY_RESULT, &queryElapsed);
					// (use the EXT-suffixed function here, as defined by GL_EXT_timer_query)
				ogl_WarnIfError();
				t += (double)queryElapsed / 1e9;
			}

			PopFrontFrame();
		}
	}
Exemple #10
0
	// Returns a new GL query object (or a recycled old one)
	GLuint NewQuery()
	{
		if (m_FreeQueries.empty())
		{
			// Generate a batch of new queries
			m_FreeQueries.resize(8);
			pglGenQueriesARB(m_FreeQueries.size(), &m_FreeQueries[0]);
			ogl_WarnIfError();
		}

		GLuint query = m_FreeQueries.back();
		m_FreeQueries.pop_back();
		return query;
	}
Exemple #11
0
	void RecordRegion(const char* id, bool isEnter)
	{
		ENSURE(!m_Frames.empty());
		SFrame& frame = m_Frames.back();

		SEvent event;
		event.id = id;
		event.query = NewQuery();
		event.isEnter = isEnter;

		pglQueryCounter(event.query, GL_TIMESTAMP);
		ogl_WarnIfError();

		frame.events.push_back(event);
	}
Exemple #12
0
	GLuint NewQuery(size_t queryIdx)
	{
		ENSURE(queryIdx < m_QueryTypes.size());

		if (m_QueryTypes[queryIdx].freeQueries.empty())
		{
			GLuint id;
			pglCreatePerfQueryINTEL(m_QueryTypes[queryIdx].queryTypeId, &id);
			ogl_WarnIfError();
			return id;
		}

		GLuint id = m_QueryTypes[queryIdx].freeQueries.back();
		m_QueryTypes[queryIdx].freeQueries.pop_back();
		return id;
	}
Exemple #13
0
	void FrameStart()
	{
		ProcessFrames();

		SFrame frame;
		frame.num = m_Profiler.GetFrameNumber();

		// On (at least) some NVIDIA Windows drivers, when GPU-bound, or when
		// vsync enabled and not CPU-bound, the first glGet* call at the start
		// of a frame appears to trigger a wait (to stop the GPU getting too
		// far behind, or to wait for the vsync period).
		// That will be this GL_TIMESTAMP get, which potentially distorts the
		// reported results. So we'll only do it fairly rarely, and for most
		// frames we'll just assume the clocks don't drift much
		
		const double RESYNC_PERIOD = 1.0; // seconds

		double now = m_Profiler.GetTime();

		if (m_Frames.empty() || now > m_Frames.back().syncTimeStart + RESYNC_PERIOD)
		{
			PROFILE2("profile timestamp resync");

			pglGetInteger64v(GL_TIMESTAMP, &frame.syncTimestampStart);
			ogl_WarnIfError();

			frame.syncTimeStart = m_Profiler.GetTime();
			// (Have to do GetTime again after GL_TIMESTAMP, because GL_TIMESTAMP
			// might wait a while before returning its now-current timestamp)
		}
		else
		{
			// Reuse the previous frame's sync data
			frame.syncTimeStart = m_Frames[m_Frames.size()-1].syncTimeStart;
			frame.syncTimestampStart = m_Frames[m_Frames.size()-1].syncTimestampStart;
		}

		m_Frames.push_back(frame);

		RegionEnter("frame");
	}
Exemple #14
0
	void RegionEnter(const char* id)
	{
		ENSURE(!m_Frames.empty());
		SFrame& frame = m_Frames.back();

		SEvent event;
		event.id = id;
		event.isEnter = true;

		for (size_t i = 0; i < m_QueryTypes.size(); ++i)
		{
			GLuint id = NewQuery(i);
			pglBeginPerfQueryINTEL(id);
			ogl_WarnIfError();
			event.queries.push_back(id);
		}

		frame.activeRegions.push_back(frame.events.size());

		frame.events.push_back(event);
	}
Exemple #15
0
	void RegionLeave(const char* id)
	{
		ENSURE(!m_Frames.empty());
		SFrame& frame = m_Frames.back();

		ENSURE(!frame.activeRegions.empty());
		SEvent& activeEvent = frame.events[frame.activeRegions.back()];

		for (size_t i = 0; i < m_QueryTypes.size(); ++i)
		{
			pglEndPerfQueryINTEL(activeEvent.queries[i]);
			ogl_WarnIfError();
		}

		frame.activeRegions.pop_back();

		SEvent event;
		event.id = id;
		event.isEnter = false;
		frame.events.push_back(event);
	}
Exemple #16
0
void Render()
{
	PROFILE3("render");

	if (g_SoundManager)
		g_SoundManager->IdleTask();

	ogl_WarnIfError();

	g_Profiler2.RecordGPUFrameStart();

	ogl_WarnIfError();

	// prepare before starting the renderer frame
	if (g_Game && g_Game->IsGameStarted())
		g_Game->GetView()->BeginFrame();

	if (g_Game)
		g_Renderer.SetSimulation(g_Game->GetSimulation2());

	// start new frame
	g_Renderer.BeginFrame();

	ogl_WarnIfError();

	if (g_Game && g_Game->IsGameStarted())
		g_Game->GetView()->Render();

	ogl_WarnIfError();

	g_Renderer.RenderTextOverlays();

	if (g_DoRenderGui)
		g_GUI->Draw();

	ogl_WarnIfError();

	// If we're in Atlas game view, render special overlays (e.g. editor bandbox)
	if (g_AtlasGameLoop && g_AtlasGameLoop->view)
	{
		g_AtlasGameLoop->view->DrawOverlays();
		ogl_WarnIfError();
	}

	// Text:

 	glDisable(GL_DEPTH_TEST);

	g_Console->Render();

	ogl_WarnIfError();

	if (g_DoRenderLogger)
		g_Logger->Render();

	ogl_WarnIfError();

	// Profile information

	g_ProfileViewer.RenderProfile();

	ogl_WarnIfError();

	// Draw the cursor (or set the Windows cursor, on Windows)
	if (g_DoRenderCursor)
	{
		PROFILE3_GPU("cursor");
		CStrW cursorName = g_CursorName;
		if (cursorName.empty())
		{
			cursor_draw(g_VFS, NULL, g_mouse_x, g_yres-g_mouse_y, false);
		}
		else
		{
			bool forceGL = false;
			CFG_GET_VAL("nohwcursor", forceGL);

#if CONFIG2_GLES
#warning TODO: implement cursors for GLES
#else
			// set up transform for GL cursor
			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();
			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();
			glLoadIdentity();
			CMatrix3D transform;
			transform.SetOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.f, 1000.f);
			glLoadMatrixf(&transform._11);
#endif

#if OS_ANDROID
#warning TODO: cursors for Android
#else
			if (cursor_draw(g_VFS, cursorName.c_str(), g_mouse_x, g_yres-g_mouse_y, forceGL) < 0)
				LOGWARNING("Failed to draw cursor '%s'", utf8_from_wstring(cursorName));
#endif

#if CONFIG2_GLES
#warning TODO: implement cursors for GLES
#else
			// restore transform
			glMatrixMode(GL_PROJECTION);
			glPopMatrix();
			glMatrixMode(GL_MODELVIEW);
			glPopMatrix();
#endif
		}
	}

	glEnable(GL_DEPTH_TEST);

	g_Renderer.EndFrame();

	PROFILE2_ATTR("draw calls: %d", (int)g_Renderer.GetStats().m_DrawCalls);
	PROFILE2_ATTR("terrain tris: %d", (int)g_Renderer.GetStats().m_TerrainTris);
	PROFILE2_ATTR("water tris: %d", (int)g_Renderer.GetStats().m_WaterTris);
	PROFILE2_ATTR("model tris: %d", (int)g_Renderer.GetStats().m_ModelTris);
	PROFILE2_ATTR("overlay tris: %d", (int)g_Renderer.GetStats().m_OverlayTris);
	PROFILE2_ATTR("blend splats: %d", (int)g_Renderer.GetStats().m_BlendSplats);
	PROFILE2_ATTR("particles: %d", (int)g_Renderer.GetStats().m_Particles);

	ogl_WarnIfError();

	g_Profiler2.RecordGPUFrameEnd();

	ogl_WarnIfError();
}
Exemple #17
0
void InitGraphics(const CmdLineArgs& args, int flags)
{
	const bool setup_vmode = (flags & INIT_HAVE_VMODE) == 0;

	if(setup_vmode)
	{
		InitSDL();

		if (!g_VideoMode.InitSDL())
			throw PSERROR_System_VmodeFailed(); // abort startup

#if !SDL_VERSION_ATLEAST(2, 0, 0)
		SDL_WM_SetCaption("0 A.D.", "0 A.D.");
#endif
	}

	RunHardwareDetection();

	tex_codec_register_all();

	const int quality = SANE_TEX_QUALITY_DEFAULT;	// TODO: set value from config file
	SetTextureQuality(quality);

	ogl_WarnIfError();

	// Optionally start profiler GPU timings automatically
	// (By default it's only enabled by a hotkey, for performance/compatibility)
	bool profilerGPUEnable = false;
	CFG_GET_VAL("profiler2.gpu.autoenable", Bool, profilerGPUEnable);
	if (profilerGPUEnable)
		g_Profiler2.EnableGPU();

	if(!g_Quickstart)
	{
		WriteSystemInfo();
		// note: no longer vfs_display here. it's dog-slow due to unbuffered
		// file output and very rarely needed.
	}

	if(g_DisableAudio)
	{
		// speed up startup by disabling all sound
		// (OpenAL init will be skipped).
		// must be called before first snd_open.
#if CONFIG2_AUDIO
		CSoundManager::SetEnabled(false);
#endif
	}

	g_GUI = new CGUIManager(g_ScriptingHost.GetScriptInterface());

	// (must come after SetVideoMode, since it calls ogl_Init)
	const char* missing = ogl_HaveExtensions(0,
		"GL_ARB_multitexture",
		"GL_EXT_draw_range_elements",
		"GL_ARB_texture_env_combine",
		"GL_ARB_texture_env_dot3",
		NULL);
	if(missing)
	{
		wchar_t buf[500];
		swprintf_s(buf, ARRAY_SIZE(buf),
			L"The %hs extension doesn't appear to be available on your computer."
			L" The game may still work, though - you are welcome to try at your own risk."
			L" If not or it doesn't look right, upgrade your graphics card.",
			missing
		);
		DEBUG_DISPLAY_ERROR(buf);
		// TODO: i18n
	}

	if (!ogl_HaveExtension("GL_ARB_texture_env_crossbar"))
	{
		DEBUG_DISPLAY_ERROR(
			L"The GL_ARB_texture_env_crossbar extension doesn't appear to be available on your computer."
			L" Shadows are not available and overall graphics quality might suffer."
			L" You are advised to try installing newer drivers and/or upgrade your graphics card.");
		g_Shadows = false;
	}

	ogl_WarnIfError();
	InitRenderer();

	InitInput();

	ogl_WarnIfError();

	try
	{
		if (!Autostart(args))
		{
			const bool setup_gui = ((flags & INIT_NO_GUI) == 0);
			// We only want to display the splash screen at startup
			CScriptValRooted data;
			if (g_GUI)
			{
				ScriptInterface& scriptInterface = g_GUI->GetScriptInterface();
				scriptInterface.Eval("({})", data);
				scriptInterface.SetProperty(data.get(), "isStartup", true);
			}
			InitPs(setup_gui, L"page_pregame.xml", data.get());
		}
	}
	catch (PSERROR_Game_World_MapLoadFailed e)
	{
		// Map Loading failed

		// Start the engine so we have a GUI
		InitPs(true, L"page_pregame.xml", JSVAL_VOID);

		// Call script function to do the actual work
		//	(delete game data, switch GUI page, show error, etc.)
		CancelLoad(CStr(e.what()).FromUTF8());
	}
}
Exemple #18
0
static void Frame()
{
	g_Profiler2.RecordFrameStart();
	PROFILE2("frame");
	g_Profiler2.IncrementFrameNumber();
	PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber());

	ogl_WarnIfError();

	// get elapsed time
	const double time = timer_Time();
	g_frequencyFilter->Update(time);
	// .. old method - "exact" but contains jumps
#if 0
	static double last_time;
	const double time = timer_Time();
	const float TimeSinceLastFrame = (float)(time-last_time);
	last_time = time;
	ONCE(return);	// first call: set last_time and return

	// .. new method - filtered and more smooth, but errors may accumulate
#else
	const float realTimeSinceLastFrame = 1.0 / g_frequencyFilter->SmoothedFrequency();
#endif
	ENSURE(realTimeSinceLastFrame > 0.0f);

	// decide if update/render is necessary
	bool need_render = !g_app_minimized;
	bool need_update = true;

	// If we are not running a multiplayer game, disable updates when the game is
	// minimized or out of focus and relinquish the CPU a bit, in order to make 
	// debugging easier.
	if(g_PauseOnFocusLoss && !g_NetClient && !g_app_has_focus)
	{
		PROFILE3("non-focus delay");
		need_update = false;
		// don't use SDL_WaitEvent: don't want the main loop to freeze until app focus is restored
		SDL_Delay(10);
	}

	// TODO: throttling: limit update and render frequency to the minimum.
	// this is mostly relevant for "inactive" state, so that other windows
	// get enough CPU time, but it's always nice for power+thermal management.


	// this scans for changed files/directories and reloads them, thus
	// allowing hotloading (changes are immediately assimilated in-game).
	ReloadChangedFiles();

	ProgressiveLoad();

	RendererIncrementalLoad();

	PumpEvents();

	// if the user quit by closing the window, the GL context will be broken and
	// may crash when we call Render() on some drivers, so leave this loop
	// before rendering
	if (quit)
		return;

	// respond to pumped resize events
	if (g_ResizedW || g_ResizedH)
	{
		g_VideoMode.ResizeWindow(g_ResizedW, g_ResizedH);
		g_ResizedW = g_ResizedH = 0;
	}

	if (g_NetClient)
		g_NetClient->Poll();

	ogl_WarnIfError();

	g_GUI->TickObjects();

	ogl_WarnIfError();

	if (g_Game && g_Game->IsGameStarted() && need_update)
	{
		g_Game->Update(realTimeSinceLastFrame);

		g_Game->GetView()->Update(float(realTimeSinceLastFrame));
	}

	// Immediately flush any messages produced by simulation code
	if (g_NetClient)
		g_NetClient->Flush();

	g_UserReporter.Update();

	g_Console->Update(realTimeSinceLastFrame);

	ogl_WarnIfError();
	if(need_render)
	{
		Render();

		PROFILE3("swap buffers");
#if SDL_VERSION_ATLEAST(2, 0, 0)
		SDL_GL_SwapWindow(g_VideoMode.GetWindow());
#else
		SDL_GL_SwapBuffers();
#endif
	}
	ogl_WarnIfError();

	g_Profiler.Frame();

	g_GameRestarted = false;
}
Exemple #19
0
void OverlayRenderer::RenderQuadOverlays()
{
	if (m->quadBatchMap.empty())
		return;

	ogl_WarnIfError();

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glDepthMask(0);

	const char* shaderName;
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
		shaderName = "arb/overlayline";
	else
		shaderName = "fixed:overlayline";

	CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();

	CShaderManager& shaderManager = g_Renderer.GetShaderManager();
	CShaderProgramPtr shader(shaderManager.LoadProgram(shaderName, m->defsQuadOverlay));

	// ----------------------------------------------------------------------------------------

	if (shader)
	{
		shader->Bind();
		shader->BindTexture("losTex", los.GetTexture());
		shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);

		// Base offsets (in bytes) of the two backing stores relative to their owner VBO
		u8* indexBase = m->quadIndices.Bind();
		u8* vertexBase = m->quadVertices.Bind();
		GLsizei indexStride = m->quadIndices.GetStride();
		GLsizei vertexStride = m->quadVertices.GetStride();

		for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); it++)
		{
			QuadBatchData& batchRenderData = it->second;
			const size_t batchNumQuads = batchRenderData.m_NumRenderQuads;

			// Careful; some drivers don't like drawing calls with 0 stuff to draw.
			if (batchNumQuads == 0)
				continue;

			const QuadBatchKey& maskPair = it->first;

			shader->BindTexture("baseTex", maskPair.m_Texture->GetHandle());
			shader->BindTexture("maskTex", maskPair.m_TextureMask->GetHandle());

			int streamflags = shader->GetStreamFlags();

			if (streamflags & STREAM_POS)
				shader->VertexPointer(m->quadAttributePos.elems, m->quadAttributePos.type, vertexStride, vertexBase + m->quadAttributePos.offset);

			if (streamflags & STREAM_UV0)
				shader->TexCoordPointer(GL_TEXTURE0, m->quadAttributeUV.elems, m->quadAttributeUV.type, vertexStride, vertexBase + m->quadAttributeUV.offset);

			if (streamflags & STREAM_UV1)
				shader->TexCoordPointer(GL_TEXTURE1, m->quadAttributeUV.elems, m->quadAttributeUV.type, vertexStride, vertexBase + m->quadAttributeUV.offset);
			
			if (streamflags & STREAM_COLOR)
				shader->ColorPointer(m->quadAttributeColor.elems, m->quadAttributeColor.type, vertexStride, vertexBase + m->quadAttributeColor.offset);
			
			shader->AssertPointersBound();
			glDrawElements(GL_TRIANGLES, (GLsizei)(batchNumQuads * 6), GL_UNSIGNED_SHORT, indexBase + indexStride * batchRenderData.m_IndicesBase);

			g_Renderer.GetStats().m_DrawCalls++;
			g_Renderer.GetStats().m_OverlayTris += batchNumQuads*2;
		}

		shader->Unbind();
	}

	// ----------------------------------------------------------------------------------------

	// TODO: the shader should probably be responsible for unbinding its textures
	g_Renderer.BindTexture(1, 0);
	g_Renderer.BindTexture(0, 0);

	CVertexBuffer::Unbind();

	glDepthMask(1);
	glDisable(GL_BLEND);
}
Exemple #20
0
void OverlayRenderer::RenderTexturedOverlayLines()
{
#if CONFIG2_GLES
#warning TODO: implement OverlayRenderer::RenderTexturedOverlayLines for GLES
	return;
#endif
	if (m->texlines.empty())
		return;

	ogl_WarnIfError();

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glDepthMask(0);

	const char* shaderName;
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
		shaderName = "arb/overlayline";
	else
		shaderName = "fixed:overlayline";

	CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();

	CShaderManager& shaderManager = g_Renderer.GetShaderManager();
	CShaderProgramPtr shaderTexLineNormal(shaderManager.LoadProgram(shaderName, m->defsOverlayLineNormal));
	CShaderProgramPtr shaderTexLineAlwaysVisible(shaderManager.LoadProgram(shaderName, m->defsOverlayLineAlwaysVisible));

	// ----------------------------------------------------------------------------------------

	if (shaderTexLineNormal)
	{
		shaderTexLineNormal->Bind();
		shaderTexLineNormal->BindTexture("losTex", los.GetTexture());
		shaderTexLineNormal->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);

		// batch render only the non-always-visible overlay lines using the normal shader
		RenderTexturedOverlayLines(shaderTexLineNormal, false);

		shaderTexLineNormal->Unbind();
	}

	// ----------------------------------------------------------------------------------------

	if (shaderTexLineAlwaysVisible)
	{
		shaderTexLineAlwaysVisible->Bind();
		// TODO: losTex and losTransform are unused in the always visible shader; see if these can be safely omitted
		shaderTexLineAlwaysVisible->BindTexture("losTex", los.GetTexture());
		shaderTexLineAlwaysVisible->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);

		// batch render only the always-visible overlay lines using the LoS-ignored shader
		RenderTexturedOverlayLines(shaderTexLineAlwaysVisible, true);

		shaderTexLineAlwaysVisible->Unbind();
	}

	// ----------------------------------------------------------------------------------------

	// TODO: the shaders should probably be responsible for unbinding their textures
	g_Renderer.BindTexture(1, 0);
	g_Renderer.BindTexture(0, 0);

	CVertexBuffer::Unbind();

	glDepthMask(1);
	glDisable(GL_BLEND);
}
Exemple #21
0
static void ReportGLLimits(ScriptInterface& scriptInterface, CScriptValRooted settings)
{
	const char* errstr = "(error)";

#define INTEGER(id) do { \
	GLint i = -1; \
	glGetIntegerv(GL_##id, &i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings.get(), "GL_" #id, errstr); \
	else \
		scriptInterface.SetProperty(settings.get(), "GL_" #id, i); \
	} while (false)

#define INTEGER2(id) do { \
	GLint i[2] = { -1, -1 }; \
	glGetIntegerv(GL_##id, i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) { \
		scriptInterface.SetProperty(settings.get(), "GL_" #id "[0]", errstr); \
		scriptInterface.SetProperty(settings.get(), "GL_" #id "[1]", errstr); \
	} else { \
		scriptInterface.SetProperty(settings.get(), "GL_" #id "[0]", i[0]); \
		scriptInterface.SetProperty(settings.get(), "GL_" #id "[1]", i[1]); \
	} \
	} while (false)

#define FLOAT(id) do { \
	GLfloat f = std::numeric_limits<GLfloat>::quiet_NaN(); \
	glGetFloatv(GL_##id, &f); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings.get(), "GL_" #id, errstr); \
	else \
		scriptInterface.SetProperty(settings.get(), "GL_" #id, f); \
	} while (false)

#define FLOAT2(id) do { \
	GLfloat f[2] = { std::numeric_limits<GLfloat>::quiet_NaN(), std::numeric_limits<GLfloat>::quiet_NaN() }; \
	glGetFloatv(GL_##id, f); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) { \
		scriptInterface.SetProperty(settings.get(), "GL_" #id "[0]", errstr); \
		scriptInterface.SetProperty(settings.get(), "GL_" #id "[1]", errstr); \
	} else { \
		scriptInterface.SetProperty(settings.get(), "GL_" #id "[0]", f[0]); \
		scriptInterface.SetProperty(settings.get(), "GL_" #id "[1]", f[1]); \
	} \
	} while (false)

#define STRING(id) do { \
	const char* c = (const char*)glGetString(GL_##id); \
	if (!c) c = ""; \
	if (ogl_SquelchError(GL_INVALID_ENUM)) c = errstr; \
	scriptInterface.SetProperty(settings.get(), "GL_" #id, std::string(c)); \
	}  while (false)

#define QUERY(target, pname) do { \
	GLint i = -1; \
	pglGetQueryivARB(GL_##target, GL_##pname, &i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings.get(), "GL_" #target ".GL_" #pname, errstr); \
	else \
		scriptInterface.SetProperty(settings.get(), "GL_" #target ".GL_" #pname, i); \
	} while (false)

#define VERTEXPROGRAM(id) do { \
	GLint i = -1; \
	pglGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_##id, &i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings.get(), "GL_VERTEX_PROGRAM_ARB.GL_" #id, errstr); \
	else \
		scriptInterface.SetProperty(settings.get(), "GL_VERTEX_PROGRAM_ARB.GL_" #id, i); \
	} while (false)

#define FRAGMENTPROGRAM(id) do { \
	GLint i = -1; \
	pglGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_##id, &i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings.get(), "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, errstr); \
	else \
		scriptInterface.SetProperty(settings.get(), "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, i); \
	} while (false)

#define BOOL(id) INTEGER(id)

	ogl_WarnIfError();

	// Core OpenGL 1.3:
	// (We don't bother checking extension strings for anything older than 1.3;
	// it'll just produce harmless warnings)
	STRING(VERSION);
	STRING(VENDOR);
	STRING(RENDERER);
	STRING(EXTENSIONS);
#if !CONFIG2_GLES
	INTEGER(MAX_LIGHTS);
	INTEGER(MAX_CLIP_PLANES);
	// Skip MAX_COLOR_MATRIX_STACK_DEPTH (only in imaging subset)
	INTEGER(MAX_MODELVIEW_STACK_DEPTH);
	INTEGER(MAX_PROJECTION_STACK_DEPTH);
	INTEGER(MAX_TEXTURE_STACK_DEPTH);
#endif
	INTEGER(SUBPIXEL_BITS);
#if !CONFIG2_GLES
	INTEGER(MAX_3D_TEXTURE_SIZE);
#endif
	INTEGER(MAX_TEXTURE_SIZE);
	INTEGER(MAX_CUBE_MAP_TEXTURE_SIZE);
#if !CONFIG2_GLES
	INTEGER(MAX_PIXEL_MAP_TABLE);
	INTEGER(MAX_NAME_STACK_DEPTH);
	INTEGER(MAX_LIST_NESTING);
	INTEGER(MAX_EVAL_ORDER);
#endif
	INTEGER2(MAX_VIEWPORT_DIMS);
#if !CONFIG2_GLES
	INTEGER(MAX_ATTRIB_STACK_DEPTH);
	INTEGER(MAX_CLIENT_ATTRIB_STACK_DEPTH);
	INTEGER(AUX_BUFFERS);
	BOOL(RGBA_MODE);
	BOOL(INDEX_MODE);
	BOOL(DOUBLEBUFFER);
	BOOL(STEREO);
#endif
	FLOAT2(ALIASED_POINT_SIZE_RANGE);
#if !CONFIG2_GLES
	FLOAT2(SMOOTH_POINT_SIZE_RANGE);
	FLOAT(SMOOTH_POINT_SIZE_GRANULARITY);
#endif
	FLOAT2(ALIASED_LINE_WIDTH_RANGE);
#if !CONFIG2_GLES
	FLOAT2(SMOOTH_LINE_WIDTH_RANGE);
	FLOAT(SMOOTH_LINE_WIDTH_GRANULARITY);
	// Skip MAX_CONVOLUTION_WIDTH, MAX_CONVOLUTION_HEIGHT (only in imaging subset)
	INTEGER(MAX_ELEMENTS_INDICES);
	INTEGER(MAX_ELEMENTS_VERTICES);
	INTEGER(MAX_TEXTURE_UNITS);
#endif
	INTEGER(SAMPLE_BUFFERS);
	INTEGER(SAMPLES);
	// TODO: compressed texture formats
	INTEGER(RED_BITS);
	INTEGER(GREEN_BITS);
	INTEGER(BLUE_BITS);
	INTEGER(ALPHA_BITS);
#if !CONFIG2_GLES
	INTEGER(INDEX_BITS);
#endif
	INTEGER(DEPTH_BITS);
	INTEGER(STENCIL_BITS);
#if !CONFIG2_GLES
	INTEGER(ACCUM_RED_BITS);
	INTEGER(ACCUM_GREEN_BITS);
	INTEGER(ACCUM_BLUE_BITS);
	INTEGER(ACCUM_ALPHA_BITS);
#endif

#if !CONFIG2_GLES

	// Core OpenGL 2.0 (treated as extensions):

	if (ogl_HaveExtension("GL_EXT_texture_lod_bias"))
	{
		FLOAT(MAX_TEXTURE_LOD_BIAS_EXT);
	}

	if (ogl_HaveExtension("GL_ARB_occlusion_query"))
	{
		QUERY(SAMPLES_PASSED, QUERY_COUNTER_BITS);
	}

	if (ogl_HaveExtension("GL_ARB_shading_language_100"))
	{
		STRING(SHADING_LANGUAGE_VERSION_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_vertex_shader"))
	{
		INTEGER(MAX_VERTEX_ATTRIBS_ARB);
		INTEGER(MAX_VERTEX_UNIFORM_COMPONENTS_ARB);
		INTEGER(MAX_VARYING_FLOATS_ARB);
		INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB);
		INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_fragment_shader"))
	{
		INTEGER(MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_vertex_shader") || ogl_HaveExtension("GL_ARB_fragment_shader") ||
		ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program"))
	{
		INTEGER(MAX_TEXTURE_IMAGE_UNITS_ARB);
		INTEGER(MAX_TEXTURE_COORDS_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_draw_buffers"))
	{
		INTEGER(MAX_DRAW_BUFFERS_ARB);
	}

	// Core OpenGL 3.0:

	if (ogl_HaveExtension("GL_EXT_gpu_shader4"))
	{
		INTEGER(MIN_PROGRAM_TEXEL_OFFSET); // no _EXT version of these in glext.h
		INTEGER(MAX_PROGRAM_TEXEL_OFFSET);
	}

	if (ogl_HaveExtension("GL_EXT_framebuffer_object"))
	{
		INTEGER(MAX_COLOR_ATTACHMENTS_EXT);
		INTEGER(MAX_RENDERBUFFER_SIZE_EXT);
	}

	if (ogl_HaveExtension("GL_EXT_framebuffer_multisample"))
	{
		INTEGER(MAX_SAMPLES_EXT);
	}

	if (ogl_HaveExtension("GL_EXT_texture_array"))
	{
		INTEGER(MAX_ARRAY_TEXTURE_LAYERS_EXT);
	}

	if (ogl_HaveExtension("GL_EXT_transform_feedback"))
	{
		INTEGER(MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT);
		INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT);
		INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT);
	}


	// Other interesting extensions:

	if (ogl_HaveExtension("GL_EXT_timer_query") || ogl_HaveExtension("GL_ARB_timer_query"))
	{
		QUERY(TIME_ELAPSED, QUERY_COUNTER_BITS);
	}

	if (ogl_HaveExtension("GL_ARB_timer_query"))
	{
		QUERY(TIMESTAMP, QUERY_COUNTER_BITS);
	}

	if (ogl_HaveExtension("GL_EXT_texture_filter_anisotropic"))
	{
		FLOAT(MAX_TEXTURE_MAX_ANISOTROPY_EXT);
	}

	if (ogl_HaveExtension("GL_ARB_texture_rectangle"))
	{
		INTEGER(MAX_RECTANGLE_TEXTURE_SIZE_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program"))
	{
		INTEGER(MAX_PROGRAM_MATRICES_ARB);
		INTEGER(MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_vertex_program"))
	{
		VERTEXPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_PARAMETERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_ATTRIBS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB);

		if (ogl_HaveExtension("GL_ARB_fragment_program"))
		{
			// The spec seems to say these should be supported, but
			// Mesa complains about them so let's not bother
			/*
			VERTEXPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB);
			*/
		}
	}

	if (ogl_HaveExtension("GL_ARB_fragment_program"))
	{
		FRAGMENTPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_PARAMETERS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_ATTRIBS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB);

		if (ogl_HaveExtension("GL_ARB_vertex_program"))
		{
			// The spec seems to say these should be supported, but
			// Intel drivers on Windows complain about them so let's not bother
			/*
			FRAGMENTPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB);
			FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB);
			*/
		}
	}

	if (ogl_HaveExtension("GL_ARB_geometry_shader4"))
	{
		INTEGER(MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB);
		INTEGER(MAX_GEOMETRY_OUTPUT_VERTICES_ARB);
		INTEGER(MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB);
		INTEGER(MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB);
		INTEGER(MAX_GEOMETRY_VARYING_COMPONENTS_ARB);
		INTEGER(MAX_VERTEX_VARYING_COMPONENTS_ARB);
	}

#else // CONFIG2_GLES

	// Core OpenGL ES 2.0:

	STRING(SHADING_LANGUAGE_VERSION);
	INTEGER(MAX_VERTEX_ATTRIBS);
	INTEGER(MAX_VERTEX_UNIFORM_VECTORS);
	INTEGER(MAX_VARYING_VECTORS);
	INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
	INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS);
	INTEGER(MAX_FRAGMENT_UNIFORM_VECTORS);
	INTEGER(MAX_TEXTURE_IMAGE_UNITS);
	INTEGER(MAX_RENDERBUFFER_SIZE);

#endif // CONFIG2_GLES
}
Exemple #22
0
	bool Link()
	{
		TIMER_ACCRUE(tc_ShaderGLSLLink);

		ENSURE(!m_Program);
		m_Program = pglCreateProgramObjectARB();

		pglAttachObjectARB(m_Program, m_VertexShader);
		ogl_WarnIfError();
		pglAttachObjectARB(m_Program, m_FragmentShader);
		ogl_WarnIfError();

		// Set up the attribute bindings explicitly, since apparently drivers
		// don't always pick the most efficient bindings automatically,
		// and also this lets us hardcode indexes into VertexPointer etc
		for (std::map<CStrIntern, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
			pglBindAttribLocationARB(m_Program, it->second, it->first.c_str());

		pglLinkProgramARB(m_Program);

		GLint ok = 0;
		pglGetProgramiv(m_Program, GL_LINK_STATUS, &ok);

		GLint length = 0;
		pglGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length);

		if (!ok && length == 0)
			length = 4096;

		if (length > 1)
		{
			char* infolog = new char[length];
			pglGetProgramInfoLog(m_Program, length, NULL, infolog);

			if (ok)
				LOGMESSAGE(L"Info when linking program '%ls'+'%ls':\n%hs", m_VertexFile.string().c_str(), m_FragmentFile.string().c_str(), infolog);
			else
				LOGERROR(L"Failed to link program '%ls'+'%ls':\n%hs", m_VertexFile.string().c_str(), m_FragmentFile.string().c_str(), infolog);
			
			delete[] infolog;
		}

		ogl_WarnIfError();

		if (!ok)
			return false;

		m_Uniforms.clear();
		m_Samplers.clear();

		Bind();

		ogl_WarnIfError();

		GLint numUniforms = 0;
		pglGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms);
		ogl_WarnIfError();
		for (GLint i = 0; i < numUniforms; ++i)
		{
			char name[256] = {0};
			GLsizei nameLength = 0;
			GLint size = 0;
			GLenum type = 0;
			pglGetActiveUniformARB(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name);
			ogl_WarnIfError();

			GLint loc = pglGetUniformLocationARB(m_Program, name);

			CStrIntern nameIntern(name);
			m_Uniforms[nameIntern] = std::make_pair(loc, type);

			// Assign sampler uniforms to sequential texture units
			if (type == GL_SAMPLER_2D
			 || type == GL_SAMPLER_CUBE
#if !CONFIG2_GLES
			 || type == GL_SAMPLER_2D_SHADOW
#endif
			)
			{
				int unit = (int)m_Samplers.size();
				m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D);
				m_Samplers[nameIntern].second = unit;
				pglUniform1iARB(loc, unit); // link uniform to unit
				ogl_WarnIfError();
			}
		}

		// TODO: verify that we're not using more samplers than is supported

		Unbind();

		ogl_WarnIfError();

		return true;
	}
Exemple #23
0
	void ProcessFrames()
	{
		while (!m_Frames.empty())
		{
			SFrame& frame = m_Frames.front();

			// Queries don't become available in order, so check them all before
			// trying to read the results from any
			for (size_t j = 0; j < m_QueryTypes.size(); ++j)
			{
				size_t size = m_QueryTypes[j].counterBufferSize;
				shared_ptr<char> buf(new char[size], ArrayDeleter());

				for (size_t i = 0; i < frame.events.size(); ++i)
				{
					if (!frame.events[i].isEnter)
						continue;

					GLuint length = 0;
					pglGetPerfQueryDataINTEL(frame.events[i].queries[j], INTEL_PERFQUERIES_NONBLOCK, size, buf.get(), &length);
					ogl_WarnIfError();
					if (length == 0)
						return;
				}
			}

			double lastTime = frame.timeStart;
			std::stack<double> endTimes;

			m_Storage.RecordFrameStart(frame.timeStart);

			for (size_t i = 0; i < frame.events.size(); ++i)
			{
				if (frame.events[i].isEnter)
				{
					m_Storage.Record(CProfiler2::ITEM_ENTER, lastTime, frame.events[i].id);

					if (i == 0)
						m_Storage.RecordAttributePrintf("%u", frame.num);

					double elapsed = 0.0;

					for (size_t j = 0; j < m_QueryTypes.size(); ++j)
					{
						GLuint length;
						char* buf = new char[m_QueryTypes[j].counterBufferSize];
						pglGetPerfQueryDataINTEL(frame.events[i].queries[j], INTEL_PERFQUERIES_BLOCK, m_QueryTypes[j].counterBufferSize, buf, &length);
						ogl_WarnIfError();
						ENSURE(length == m_QueryTypes[j].counterBufferSize);

						m_Storage.RecordAttributePrintf("-- %s --", m_QueryTypes[j].name.c_str());

						for (size_t k = 0; k < m_QueryTypes[j].counters.size(); ++k)
						{
							SPerfCounter& counter = m_QueryTypes[j].counters[k];

							if (counter.type == INTEL_PERFQUERIES_TYPE_UNSIGNED_INT)
							{
								ENSURE(counter.size == 4);
								GLuint value;
								memcpy(&value, buf + counter.offset, counter.size);
								m_Storage.RecordAttributePrintf("%s: %u", counter.name.c_str(), value);
							}
							else if (counter.type == INTEL_PERFQUERIES_TYPE_UNSIGNED_INT64)
							{
								ENSURE(counter.size == 8);
								GLuint64 value;
								memcpy(&value, buf + counter.offset, counter.size);
								m_Storage.RecordAttributePrintf("%s: %.0f", counter.name.c_str(), (double)value);

								if (counter.name == "TotalTime")
									elapsed = (double)value / 1e6;
							}
							else if (counter.type == INTEL_PERFQUERIES_TYPE_FLOAT)
							{
								ENSURE(counter.size == 4);
								GLfloat value;
								memcpy(&value, buf + counter.offset, counter.size);
								m_Storage.RecordAttributePrintf("%s: %f", counter.name.c_str(), value);
							}
							else if (counter.type == INTEL_PERFQUERIES_TYPE_BOOL)
							{
								ENSURE(counter.size == 4);
								GLuint value;
								memcpy(&value, buf + counter.offset, counter.size);
								ENSURE(value == 0 || value == 1);
								m_Storage.RecordAttributePrintf("%s: %u", counter.name.c_str(), value);
							}
							else
							{
								debug_warn(L"unrecognised Intel performance counter type");
							}
						}

						delete[] buf;
					}

					endTimes.push(lastTime + elapsed);
				}
				else
				{
					lastTime = endTimes.top();
					endTimes.pop();
					m_Storage.Record(CProfiler2::ITEM_LEAVE, lastTime, frame.events[i].id);
				}
			}

			PopFrontFrame();
		}
	}
Exemple #24
0
	~CProfiler2GPU_timer_query()
	{
		if (!m_FreeQueries.empty())
			pglDeleteQueriesARB(m_FreeQueries.size(), &m_FreeQueries[0]);
		ogl_WarnIfError();
	}
Exemple #25
0
///////////////////////////////////////////////////////////////////
// Progressive load of water textures
int WaterManager::LoadWaterTextures()
{
	// TODO: this doesn't need to be progressive-loading any more
	// (since texture loading is async now)

	wchar_t pathname[PATH_MAX];
	
	// Load diffuse grayscale images (for non-fancy water)
	for (size_t i = 0; i < ARRAY_SIZE(m_WaterTexture); ++i)
	{
		swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/default/diffuse%02d.dds", (int)i+1);
		CTextureProperties textureProps(pathname);
		textureProps.SetWrap(GL_REPEAT);

		CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
		texture->Prefetch();
		m_WaterTexture[i] = texture;
	}

	if (!g_Renderer.GetCapabilities().m_PrettyWater)
	{
		// Enable rendering, now that we've succeeded this far
		m_RenderWater = true;
		return 0;
	}

#if CONFIG2_GLES
#warning Fix WaterManager::LoadWaterTextures on GLES
#else
	// Load normalmaps (for fancy water)
	for (size_t i = 0; i < ARRAY_SIZE(m_NormalMap); ++i)
	{
		swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/%ls/normal00%02d.png", m_WaterType.c_str(), (int)i+1);
		CTextureProperties textureProps(pathname);
		textureProps.SetWrap(GL_REPEAT);
		textureProps.SetMaxAnisotropy(4);
		
		CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
		texture->Prefetch();
		m_NormalMap[i] = texture;
	}
	
	// Load CoastalWaves
	{
		CTextureProperties textureProps(L"art/textures/terrain/types/water/coastalWave.png");
		textureProps.SetWrap(GL_REPEAT);
		CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
		texture->Prefetch();
		m_WaveTex = texture;
	}
	
	// Load Foam
	{
		CTextureProperties textureProps(L"art/textures/terrain/types/water/foam.png");
		textureProps.SetWrap(GL_REPEAT);
		CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
		texture->Prefetch();
		m_FoamTex = texture;
	}
	
	// Use screen-sized textures for minimum artifacts.
	m_RefTextureSize = g_Renderer.GetHeight();
	
	m_RefTextureSize = round_up_to_pow2(m_RefTextureSize);
	
	// Create reflection texture
	glGenTextures(1, &m_ReflectionTexture);
	glBindTexture(GL_TEXTURE_2D, m_ReflectionTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_RefTextureSize, (GLsizei)m_RefTextureSize, 0,  GL_RGBA, GL_UNSIGNED_BYTE, 0);
	
	// Create refraction texture
	glGenTextures(1, &m_RefractionTexture);
	glBindTexture(GL_TEXTURE_2D, m_RefractionTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, (GLsizei)m_RefTextureSize, (GLsizei)m_RefTextureSize, 0,  GL_RGB, GL_UNSIGNED_BYTE, 0);

	// Create depth textures
	glGenTextures(1, &m_ReflFboDepthTexture);
	glBindTexture(GL_TEXTURE_2D, m_ReflFboDepthTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, (GLsizei)m_RefTextureSize, (GLsizei)m_RefTextureSize, 0,  GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
	
	glGenTextures(1, &m_RefrFboDepthTexture);
	glBindTexture(GL_TEXTURE_2D, m_RefrFboDepthTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, (GLsizei)m_RefTextureSize, (GLsizei)m_RefTextureSize, 0,  GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);

	// Create the Fancy Effects texture
	glGenTextures(1, &m_FancyTextureNormal);
	glBindTexture(GL_TEXTURE_2D, m_FancyTextureNormal);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	glGenTextures(1, &m_FancyTextureOther);
	glBindTexture(GL_TEXTURE_2D, m_FancyTextureOther);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	glGenTextures(1, &m_FancyTextureDepth);
	glBindTexture(GL_TEXTURE_2D, m_FancyTextureDepth);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	glBindTexture(GL_TEXTURE_2D, 0);

	Resize();

	// Create the water framebuffers

	GLint currentFbo;
	glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &currentFbo);

	m_ReflectionFbo = 0;
	pglGenFramebuffersEXT(1, &m_ReflectionFbo);
	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_ReflectionFbo);
	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_ReflectionTexture, 0);
	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_ReflFboDepthTexture, 0);

	ogl_WarnIfError();
	
	GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		LOGWARNING("Reflection framebuffer object incomplete: 0x%04X", status);
		g_Renderer.m_Options.m_WaterReflection = false;
	}

	m_RefractionFbo = 0;
	pglGenFramebuffersEXT(1, &m_RefractionFbo);
	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_RefractionFbo);
	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_RefractionTexture, 0);
	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_RefrFboDepthTexture, 0);

	ogl_WarnIfError();
	
	status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		LOGWARNING("Refraction framebuffer object incomplete: 0x%04X", status);
		g_Renderer.m_Options.m_WaterRefraction = false;
	}
	
	pglGenFramebuffersEXT(1, &m_FancyEffectsFBO);
	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO);
	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_FancyTextureNormal, 0);
	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, m_FancyTextureOther, 0);
	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_FancyTextureDepth, 0);
	
	ogl_WarnIfError();
	
	status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		LOGWARNING("Fancy Effects framebuffer object incomplete: 0x%04X", status);
		g_Renderer.m_Options.m_WaterRefraction = false;
	}
	
	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFbo);

	// Enable rendering, now that we've succeeded this far
	m_RenderWater = true;
#endif
	return 0;
}
Exemple #26
0
void InitGraphics(const CmdLineArgs& args, int flags)
{
	const bool setup_vmode = (flags & INIT_HAVE_VMODE) == 0;

	if(setup_vmode)
	{
		InitSDL();

		if (!g_VideoMode.InitSDL())
			throw PSERROR_System_VmodeFailed(); // abort startup

#if !SDL_VERSION_ATLEAST(2, 0, 0)
		SDL_WM_SetCaption("0 A.D.", "0 A.D.");
#endif
	}

	RunHardwareDetection();

	const int quality = SANE_TEX_QUALITY_DEFAULT;	// TODO: set value from config file
	SetTextureQuality(quality);

	ogl_WarnIfError();

	// Optionally start profiler GPU timings automatically
	// (By default it's only enabled by a hotkey, for performance/compatibility)
	bool profilerGPUEnable = false;
	CFG_GET_VAL("profiler2.autoenable", profilerGPUEnable);
	if (profilerGPUEnable)
		g_Profiler2.EnableGPU();

	if(!g_Quickstart)
	{
		WriteSystemInfo();
		// note: no longer vfs_display here. it's dog-slow due to unbuffered
		// file output and very rarely needed.
	}

	if(g_DisableAudio)
		ISoundManager::SetEnabled(false);

	g_GUI = new CGUIManager();

	// (must come after SetVideoMode, since it calls ogl_Init)
	if (ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", NULL) != 0 // ARB
		&& ogl_HaveExtensions(0, "GL_ARB_vertex_shader", "GL_ARB_fragment_shader", NULL) != 0) // GLSL
	{
		DEBUG_DISPLAY_ERROR(
			L"Your graphics card doesn't appear to be fully compatible with OpenGL shaders."
			L" In the future, the game will not support pre-shader graphics cards."
			L" You are advised to try installing newer drivers and/or upgrade your graphics card."
			L" For more information, please see http://www.wildfiregames.com/forum/index.php?showtopic=16734"
		);
		// TODO: actually quit once fixed function support is dropped
	}

	const char* missing = ogl_HaveExtensions(0,
		"GL_ARB_multitexture",
		"GL_EXT_draw_range_elements",
		"GL_ARB_texture_env_combine",
		"GL_ARB_texture_env_dot3",
		NULL);
	if(missing)
	{
		wchar_t buf[500];
		swprintf_s(buf, ARRAY_SIZE(buf),
			L"The %hs extension doesn't appear to be available on your computer."
			L" The game may still work, though - you are welcome to try at your own risk."
			L" If not or it doesn't look right, upgrade your graphics card.",
			missing
		);
		DEBUG_DISPLAY_ERROR(buf);
		// TODO: i18n
	}

	if (!ogl_HaveExtension("GL_ARB_texture_env_crossbar"))
	{
		DEBUG_DISPLAY_ERROR(
			L"The GL_ARB_texture_env_crossbar extension doesn't appear to be available on your computer."
			L" Shadows are not available and overall graphics quality might suffer."
			L" You are advised to try installing newer drivers and/or upgrade your graphics card.");
		g_Shadows = false;
	}

	ogl_WarnIfError();
	InitRenderer();

	InitInput();

	ogl_WarnIfError();

	try
	{
		if (!Autostart(args))
		{
			const bool setup_gui = ((flags & INIT_NO_GUI) == 0);
			// We only want to display the splash screen at startup
			shared_ptr<ScriptInterface> scriptInterface = g_GUI->GetScriptInterface();
			JSContext* cx = scriptInterface->GetContext();
			JSAutoRequest rq(cx);
			JS::RootedValue data(cx);
			if (g_GUI)
			{
				scriptInterface->Eval("({})", &data);
				scriptInterface->SetProperty(data, "isStartup", true);
			}
			InitPs(setup_gui, L"page_pregame.xml", g_GUI->GetScriptInterface().get(), data);
		}
	}
	catch (PSERROR_Game_World_MapLoadFailed& e)
	{
		// Map Loading failed

		// Start the engine so we have a GUI
		InitPs(true, L"page_pregame.xml", NULL, JS::UndefinedHandleValue);

		// Call script function to do the actual work
		//	(delete game data, switch GUI page, show error, etc.)
		CancelLoad(CStr(e.what()).FromUTF8());
	}
}
Exemple #27
0
//////////////////////////////////////////////////////////////////////////
// Create the shadow map
void ShadowMapInternals::CreateTexture()
{
	// Cleanup
	if (Texture)
	{
		glDeleteTextures(1, &Texture);
		Texture = 0;
	}
	if (DummyTexture)
	{
		glDeleteTextures(1, &DummyTexture);
		DummyTexture = 0;
	}
	if (Framebuffer)
	{
		pglDeleteFramebuffersEXT(1, &Framebuffer);
		Framebuffer = 0;
	}

	pglGenFramebuffersEXT(1, &Framebuffer);

	if (g_Renderer.m_ShadowMapSize != 0)
	{
		// non-default option to override the size
		Width = Height = g_Renderer.m_ShadowMapSize;
	}
	else
	{
		// get shadow map size as next power of two up from view width/height
		Width = Height = (int)round_up_to_pow2((unsigned)std::max(g_Renderer.GetWidth(), g_Renderer.GetHeight()));
	}
	// Clamp to the maximum texture size
	Width = std::min(Width, (int)ogl_max_tex_size);
	Height = std::min(Height, (int)ogl_max_tex_size);

	// Since we're using a framebuffer object, the whole texture is available
	EffectiveWidth = Width;
	EffectiveHeight = Height;

	const char* formatname;

	switch(DepthTextureBits)
	{
	case 16: formatname = "DEPTH_COMPONENT16"; break;
	case 24: formatname = "DEPTH_COMPONENT24"; break;
	case 32: formatname = "DEPTH_COMPONENT32"; break;
	default: formatname = "DEPTH_COMPONENT"; break;
	}

	LOGMESSAGE(L"Creating shadow texture (size %dx%d) (format = %hs)",
		Width, Height, formatname);


	if (g_Renderer.m_Options.m_ShadowAlphaFix)
	{
		glGenTextures(1, &DummyTexture);
		g_Renderer.BindTexture(0, DummyTexture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	}

	glGenTextures(1, &Texture);
	g_Renderer.BindTexture(0, Texture);

	GLenum format;

#if CONFIG2_GLES
	format = GL_DEPTH_COMPONENT;
#else
	switch (DepthTextureBits)
	{
	case 16: format = GL_DEPTH_COMPONENT16; break;
	case 24: format = GL_DEPTH_COMPONENT24; break;
	case 32: format = GL_DEPTH_COMPONENT32; break;
	default: format = GL_DEPTH_COMPONENT; break;
	}
#endif

	glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
	// GLES requires type == UNSIGNED_SHORT or UNSIGNED_INT

	// set texture parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

#if CONFIG2_GLES
	// GLES doesn't do depth comparisons, so treat it as a
	// basic unfiltered depth texture
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#else
	// Enable automatic depth comparisons
	glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

	// Use GL_LINEAR to trigger automatic PCF on some devices
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#endif

	ogl_WarnIfError();

	// bind to framebuffer object
	glBindTexture(GL_TEXTURE_2D, 0);
	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Framebuffer);

	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, Texture, 0);

	if (g_Renderer.m_Options.m_ShadowAlphaFix)
	{
		pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, DummyTexture, 0);
	}
	else
	{
#if CONFIG2_GLES
#warning TODO: figure out whether the glDrawBuffer/glReadBuffer stuff is needed, since it is not supported by GLES
#else
		glDrawBuffer(GL_NONE);
#endif
	}

#if !CONFIG2_GLES
	glReadBuffer(GL_NONE);
#endif

	ogl_WarnIfError();

	GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		LOGWARNING(L"Framebuffer object incomplete: 0x%04X", status);

		// Disable shadow rendering (but let the user try again if they want)
		g_Renderer.m_Options.m_Shadows = false;
	}
}
Exemple #28
0
static void ReportGLLimits(ScriptInterface& scriptInterface, JS::HandleValue settings)
{
	const char* errstr = "(error)";

#define INTEGER(id) do { \
	GLint i = -1; \
	glGetIntegerv(GL_##id, &i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings, "GL_" #id, errstr); \
	else \
		scriptInterface.SetProperty(settings, "GL_" #id, i); \
	} while (false)

#define INTEGER2(id) do { \
	GLint i[2] = { -1, -1 }; \
	glGetIntegerv(GL_##id, i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) { \
		scriptInterface.SetProperty(settings, "GL_" #id "[0]", errstr); \
		scriptInterface.SetProperty(settings, "GL_" #id "[1]", errstr); \
	} else { \
		scriptInterface.SetProperty(settings, "GL_" #id "[0]", i[0]); \
		scriptInterface.SetProperty(settings, "GL_" #id "[1]", i[1]); \
	} \
	} while (false)

#define FLOAT(id) do { \
	GLfloat f = std::numeric_limits<GLfloat>::quiet_NaN(); \
	glGetFloatv(GL_##id, &f); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings, "GL_" #id, errstr); \
	else \
		scriptInterface.SetProperty(settings, "GL_" #id, f); \
	} while (false)

#define FLOAT2(id) do { \
	GLfloat f[2] = { std::numeric_limits<GLfloat>::quiet_NaN(), std::numeric_limits<GLfloat>::quiet_NaN() }; \
	glGetFloatv(GL_##id, f); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) { \
		scriptInterface.SetProperty(settings, "GL_" #id "[0]", errstr); \
		scriptInterface.SetProperty(settings, "GL_" #id "[1]", errstr); \
	} else { \
		scriptInterface.SetProperty(settings, "GL_" #id "[0]", f[0]); \
		scriptInterface.SetProperty(settings, "GL_" #id "[1]", f[1]); \
	} \
	} while (false)

#define STRING(id) do { \
	const char* c = (const char*)glGetString(GL_##id); \
	if (!c) c = ""; \
	if (ogl_SquelchError(GL_INVALID_ENUM)) c = errstr; \
	scriptInterface.SetProperty(settings, "GL_" #id, std::string(c)); \
	}  while (false)

#define QUERY(target, pname) do { \
	GLint i = -1; \
	pglGetQueryivARB(GL_##target, GL_##pname, &i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings, "GL_" #target ".GL_" #pname, errstr); \
	else \
		scriptInterface.SetProperty(settings, "GL_" #target ".GL_" #pname, i); \
	} while (false)

#define VERTEXPROGRAM(id) do { \
	GLint i = -1; \
	pglGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_##id, &i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, errstr); \
	else \
		scriptInterface.SetProperty(settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, i); \
	} while (false)

#define FRAGMENTPROGRAM(id) do { \
	GLint i = -1; \
	pglGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_##id, &i); \
	if (ogl_SquelchError(GL_INVALID_ENUM)) \
		scriptInterface.SetProperty(settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, errstr); \
	else \
		scriptInterface.SetProperty(settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, i); \
	} while (false)

#define BOOL(id) INTEGER(id)

	ogl_WarnIfError();

	// Core OpenGL 1.3:
	// (We don't bother checking extension strings for anything older than 1.3;
	// it'll just produce harmless warnings)
	STRING(VERSION);
	STRING(VENDOR);
	STRING(RENDERER);
	STRING(EXTENSIONS);
#if !CONFIG2_GLES
	INTEGER(MAX_LIGHTS);
	INTEGER(MAX_CLIP_PLANES);
	// Skip MAX_COLOR_MATRIX_STACK_DEPTH (only in imaging subset)
	INTEGER(MAX_MODELVIEW_STACK_DEPTH);
	INTEGER(MAX_PROJECTION_STACK_DEPTH);
	INTEGER(MAX_TEXTURE_STACK_DEPTH);
#endif
	INTEGER(SUBPIXEL_BITS);
#if !CONFIG2_GLES
	INTEGER(MAX_3D_TEXTURE_SIZE);
#endif
	INTEGER(MAX_TEXTURE_SIZE);
	INTEGER(MAX_CUBE_MAP_TEXTURE_SIZE);
#if !CONFIG2_GLES
	INTEGER(MAX_PIXEL_MAP_TABLE);
	INTEGER(MAX_NAME_STACK_DEPTH);
	INTEGER(MAX_LIST_NESTING);
	INTEGER(MAX_EVAL_ORDER);
#endif
	INTEGER2(MAX_VIEWPORT_DIMS);
#if !CONFIG2_GLES
	INTEGER(MAX_ATTRIB_STACK_DEPTH);
	INTEGER(MAX_CLIENT_ATTRIB_STACK_DEPTH);
	INTEGER(AUX_BUFFERS);
	BOOL(RGBA_MODE);
	BOOL(INDEX_MODE);
	BOOL(DOUBLEBUFFER);
	BOOL(STEREO);
#endif
	FLOAT2(ALIASED_POINT_SIZE_RANGE);
#if !CONFIG2_GLES
	FLOAT2(SMOOTH_POINT_SIZE_RANGE);
	FLOAT(SMOOTH_POINT_SIZE_GRANULARITY);
#endif
	FLOAT2(ALIASED_LINE_WIDTH_RANGE);
#if !CONFIG2_GLES
	FLOAT2(SMOOTH_LINE_WIDTH_RANGE);
	FLOAT(SMOOTH_LINE_WIDTH_GRANULARITY);
	// Skip MAX_CONVOLUTION_WIDTH, MAX_CONVOLUTION_HEIGHT (only in imaging subset)
	INTEGER(MAX_ELEMENTS_INDICES);
	INTEGER(MAX_ELEMENTS_VERTICES);
	INTEGER(MAX_TEXTURE_UNITS);
#endif
	INTEGER(SAMPLE_BUFFERS);
	INTEGER(SAMPLES);
	// TODO: compressed texture formats
	INTEGER(RED_BITS);
	INTEGER(GREEN_BITS);
	INTEGER(BLUE_BITS);
	INTEGER(ALPHA_BITS);
#if !CONFIG2_GLES
	INTEGER(INDEX_BITS);
#endif
	INTEGER(DEPTH_BITS);
	INTEGER(STENCIL_BITS);
#if !CONFIG2_GLES
	INTEGER(ACCUM_RED_BITS);
	INTEGER(ACCUM_GREEN_BITS);
	INTEGER(ACCUM_BLUE_BITS);
	INTEGER(ACCUM_ALPHA_BITS);
#endif

#if !CONFIG2_GLES

	// Core OpenGL 2.0 (treated as extensions):

	if (ogl_HaveExtension("GL_EXT_texture_lod_bias"))
	{
		FLOAT(MAX_TEXTURE_LOD_BIAS_EXT);
	}

	if (ogl_HaveExtension("GL_ARB_occlusion_query"))
	{
		QUERY(SAMPLES_PASSED, QUERY_COUNTER_BITS);
	}

	if (ogl_HaveExtension("GL_ARB_shading_language_100"))
	{
		STRING(SHADING_LANGUAGE_VERSION_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_vertex_shader"))
	{
		INTEGER(MAX_VERTEX_ATTRIBS_ARB);
		INTEGER(MAX_VERTEX_UNIFORM_COMPONENTS_ARB);
		INTEGER(MAX_VARYING_FLOATS_ARB);
		INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB);
		INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_fragment_shader"))
	{
		INTEGER(MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_vertex_shader") || ogl_HaveExtension("GL_ARB_fragment_shader") ||
		ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program"))
	{
		INTEGER(MAX_TEXTURE_IMAGE_UNITS_ARB);
		INTEGER(MAX_TEXTURE_COORDS_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_draw_buffers"))
	{
		INTEGER(MAX_DRAW_BUFFERS_ARB);
	}

	// Core OpenGL 3.0:

	if (ogl_HaveExtension("GL_EXT_gpu_shader4"))
	{
		INTEGER(MIN_PROGRAM_TEXEL_OFFSET); // no _EXT version of these in glext.h
		INTEGER(MAX_PROGRAM_TEXEL_OFFSET);
	}

	if (ogl_HaveExtension("GL_EXT_framebuffer_object"))
	{
		INTEGER(MAX_COLOR_ATTACHMENTS_EXT);
		INTEGER(MAX_RENDERBUFFER_SIZE_EXT);
	}

	if (ogl_HaveExtension("GL_EXT_framebuffer_multisample"))
	{
		INTEGER(MAX_SAMPLES_EXT);
	}

	if (ogl_HaveExtension("GL_EXT_texture_array"))
	{
		INTEGER(MAX_ARRAY_TEXTURE_LAYERS_EXT);
	}

	if (ogl_HaveExtension("GL_EXT_transform_feedback"))
	{
		INTEGER(MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT);
		INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT);
		INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT);
	}


	// Other interesting extensions:

	if (ogl_HaveExtension("GL_EXT_timer_query") || ogl_HaveExtension("GL_ARB_timer_query"))
	{
		QUERY(TIME_ELAPSED, QUERY_COUNTER_BITS);
	}

	if (ogl_HaveExtension("GL_ARB_timer_query"))
	{
		QUERY(TIMESTAMP, QUERY_COUNTER_BITS);
	}

	if (ogl_HaveExtension("GL_EXT_texture_filter_anisotropic"))
	{
		FLOAT(MAX_TEXTURE_MAX_ANISOTROPY_EXT);
	}

	if (ogl_HaveExtension("GL_ARB_texture_rectangle"))
	{
		INTEGER(MAX_RECTANGLE_TEXTURE_SIZE_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program"))
	{
		INTEGER(MAX_PROGRAM_MATRICES_ARB);
		INTEGER(MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB);
	}

	if (ogl_HaveExtension("GL_ARB_vertex_program"))
	{
		VERTEXPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_PARAMETERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_ATTRIBS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB);
		VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB);

		if (ogl_HaveExtension("GL_ARB_fragment_program"))
		{
			// The spec seems to say these should be supported, but
			// Mesa complains about them so let's not bother
			/*
			VERTEXPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB);
			VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB);
			*/
		}
	}

	if (ogl_HaveExtension("GL_ARB_fragment_program"))
	{
		FRAGMENTPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_PARAMETERS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_ATTRIBS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB);
		FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB);

		if (ogl_HaveExtension("GL_ARB_vertex_program"))
		{
			// The spec seems to say these should be supported, but
			// Intel drivers on Windows complain about them so let's not bother
			/*
			FRAGMENTPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB);
			FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB);
			*/
		}
	}

	if (ogl_HaveExtension("GL_ARB_geometry_shader4"))
	{
		INTEGER(MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB);
		INTEGER(MAX_GEOMETRY_OUTPUT_VERTICES_ARB);
		INTEGER(MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB);
		INTEGER(MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB);
		INTEGER(MAX_GEOMETRY_VARYING_COMPONENTS_ARB);
		INTEGER(MAX_VERTEX_VARYING_COMPONENTS_ARB);
	}

#else // CONFIG2_GLES

	// Core OpenGL ES 2.0:

	STRING(SHADING_LANGUAGE_VERSION);
	INTEGER(MAX_VERTEX_ATTRIBS);
	INTEGER(MAX_VERTEX_UNIFORM_VECTORS);
	INTEGER(MAX_VARYING_VECTORS);
	INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
	INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS);
	INTEGER(MAX_FRAGMENT_UNIFORM_VECTORS);
	INTEGER(MAX_TEXTURE_IMAGE_UNITS);
	INTEGER(MAX_RENDERBUFFER_SIZE);

#endif // CONFIG2_GLES


#ifdef SDL_VIDEO_DRIVER_X11

#define GLXQCR_INTEGER(id) do { \
	unsigned int i = UINT_MAX; \
	if (pglXQueryCurrentRendererIntegerMESA(id, &i)) \
		scriptInterface.SetProperty(settings, #id, i); \
	} while (false)

#define GLXQCR_INTEGER2(id) do { \
	unsigned int i[2] = { UINT_MAX, UINT_MAX }; \
	if (pglXQueryCurrentRendererIntegerMESA(id, i)) { \
		scriptInterface.SetProperty(settings, #id "[0]", i[0]); \
		scriptInterface.SetProperty(settings, #id "[1]", i[1]); \
	} \
	} while (false)

#define GLXQCR_INTEGER3(id) do { \
	unsigned int i[3] = { UINT_MAX, UINT_MAX, UINT_MAX }; \
	if (pglXQueryCurrentRendererIntegerMESA(id, i)) { \
		scriptInterface.SetProperty(settings, #id "[0]", i[0]); \
		scriptInterface.SetProperty(settings, #id "[1]", i[1]); \
		scriptInterface.SetProperty(settings, #id "[2]", i[2]); \
	} \
	} while (false)

#define GLXQCR_STRING(id) do { \
	const char* str = pglXQueryCurrentRendererStringMESA(id); \
	if (str) \
		scriptInterface.SetProperty(settings, #id ".string", str); \
	} while (false)


	SDL_SysWMinfo wminfo;
	SDL_VERSION(&wminfo.version);
#if SDL_VERSION_ATLEAST(2, 0, 0)
	const int ret = SDL_GetWindowWMInfo(g_VideoMode.GetWindow(), &wminfo);
#else
	const int ret = SDL_GetWMInfo(&wminfo);
#endif
	if (ret && wminfo.subsystem == SDL_SYSWM_X11)
	{
#if SDL_VERSION_ATLEAST(2, 0, 0)
		Display* dpy = wminfo.info.x11.display;
#else
		Display* dpy = wminfo.info.x11.gfxdisplay;
#endif
		int scrnum = DefaultScreen(dpy);

		const char* glxexts = glXQueryExtensionsString(dpy, scrnum);

		scriptInterface.SetProperty(settings, "glx_extensions", glxexts);

		if (strstr(glxexts, "GLX_MESA_query_renderer") && pglXQueryCurrentRendererIntegerMESA && pglXQueryCurrentRendererStringMESA)
		{
			GLXQCR_INTEGER(GLX_RENDERER_VENDOR_ID_MESA);
			GLXQCR_INTEGER(GLX_RENDERER_DEVICE_ID_MESA);
			GLXQCR_INTEGER3(GLX_RENDERER_VERSION_MESA);
			GLXQCR_INTEGER(GLX_RENDERER_ACCELERATED_MESA);
			GLXQCR_INTEGER(GLX_RENDERER_VIDEO_MEMORY_MESA);
			GLXQCR_INTEGER(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA);
			GLXQCR_INTEGER(GLX_RENDERER_PREFERRED_PROFILE_MESA);
			GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA);
			GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA);
			GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA);
			GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA);
			GLXQCR_STRING(GLX_RENDERER_VENDOR_ID_MESA);
			GLXQCR_STRING(GLX_RENDERER_DEVICE_ID_MESA);
		}
	}
#endif // SDL_VIDEO_DRIVER_X11

}
Exemple #29
0
// Similar to WriteScreenshot, but generates an image of size 640*tiles x 480*tiles.
void WriteBigScreenshot(const VfsPath& extension, int tiles)
{
    // If the game hasn't started yet then use WriteScreenshot to generate the image.
    if(g_Game == NULL) {
        WriteScreenshot(L".bmp");
        return;
    }

    // get next available numbered filename
    // note: %04d -> always 4 digits, so sorting by filename works correctly.
    const VfsPath basenameFormat(L"screenshots/screenshot%04d");
    const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension);
    VfsPath filename;
    vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);

    // Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and
    // hope the screen is actually large enough for that.
    const int tile_w = 640, tile_h = 480;
    ENSURE(g_xres >= tile_w && g_yres >= tile_h);

    const int img_w = tile_w*tiles, img_h = tile_h*tiles;
    const int bpp = 24;
    GLenum fmt = GL_RGB;
    int flags = TEX_BOTTOM_UP;
    // we want writing BMP to be as fast as possible,
    // so read data from OpenGL in BMP format to obviate conversion.
    if(extension == L".bmp")
    {
#if !CONFIG2_GLES // GLES doesn't support BGR
        fmt = GL_BGR;
        flags |= TEX_BGR;
#endif
    }

    const size_t img_size = img_w * img_h * bpp/8;
    const size_t tile_size = tile_w * tile_h * bpp/8;
    const size_t hdr_size = tex_hdr_size(filename);
    void* tile_data = malloc(tile_size);
    if(!tile_data)
    {
        WARN_IF_ERR(ERR::NO_MEM);
        return;
    }
    shared_ptr<u8> img_buf;
    AllocateAligned(img_buf, hdr_size+img_size, maxSectorSize);

    Tex t;
    GLvoid* img = img_buf.get() + hdr_size;
    if(t.wrap(img_w, img_h, bpp, flags, img_buf, hdr_size) < 0)
    {
        free(tile_data);
        return;
    }

    ogl_WarnIfError();

    // Resize various things so that the sizes and aspect ratios are correct
    {
        g_Renderer.Resize(tile_w, tile_h);
        SViewPort vp = { 0, 0, tile_w, tile_h };
        g_Game->GetView()->GetCamera()->SetViewPort(vp);
        g_Game->GetView()->SetCameraProjection();
    }

#if !CONFIG2_GLES
    // Temporarily move everything onto the front buffer, so the user can
    // see the exciting progress as it renders (and can tell when it's finished).
    // (It doesn't just use SwapBuffers, because it doesn't know whether to
    // call the SDL version or the Atlas version.)
    GLint oldReadBuffer, oldDrawBuffer;
    glGetIntegerv(GL_READ_BUFFER, &oldReadBuffer);
    glGetIntegerv(GL_DRAW_BUFFER, &oldDrawBuffer);
    glDrawBuffer(GL_FRONT);
    glReadBuffer(GL_FRONT);
#endif

    // Hide the cursor
    CStrW oldCursor = g_CursorName;
    g_CursorName = L"";

    // Render each tile
    for (int tile_y = 0; tile_y < tiles; ++tile_y)
    {
        for (int tile_x = 0; tile_x < tiles; ++tile_x)
        {
            // Adjust the camera to render the appropriate region
            g_Game->GetView()->GetCamera()->SetProjectionTile(tiles, tile_x, tile_y);

            RenderLogger(false);
            RenderGui(false);
            Render();
            RenderGui(true);
            RenderLogger(true);

            // Copy the tile pixels into the main image
            glReadPixels(0, 0, tile_w, tile_h, fmt, GL_UNSIGNED_BYTE, tile_data);
            for (int y = 0; y < tile_h; ++y)
            {
                void* dest = (char*)img + ((tile_y*tile_h + y) * img_w + (tile_x*tile_w)) * bpp/8;
                void* src = (char*)tile_data + y * tile_w * bpp/8;
                memcpy(dest, src, tile_w * bpp/8);
            }
        }
    }

    // Restore the old cursor
    g_CursorName = oldCursor;

#if !CONFIG2_GLES
    // Restore the buffer settings
    glDrawBuffer(oldDrawBuffer);
    glReadBuffer(oldReadBuffer);
#endif

    // Restore the viewport settings
    {
        g_Renderer.Resize(g_xres, g_yres);
        SViewPort vp = { 0, 0, g_xres, g_yres };
        g_Game->GetView()->GetCamera()->SetViewPort(vp);
        g_Game->GetView()->SetCameraProjection();
        g_Game->GetView()->GetCamera()->SetProjectionTile(1, 0, 0);
    }

    if (tex_write(&t, filename) == INFO::OK)
    {
        OsPath realPath;
        g_VFS->GetRealPath(filename, realPath);

        LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());

        debug_printf(
            CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
            realPath.string8().c_str());
    }
    else
        LOGERROR("Error writing screenshot to '%s'", filename.string8());

    free(tile_data);
}
Exemple #30
0
void ActorViewer::Render()
{
	m.Terrain.MakeDirty(RENDERDATA_UPDATE_COLOR);

	g_Renderer.SetClearColor(m.Background);

	// Disable shadows locally (avoid clobbering global state)
	bool oldShadows = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
	g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, m.ShadowsEnabled);

	bool oldSky = g_Renderer.GetSkyManager()->m_RenderSky;
	g_Renderer.GetSkyManager()->m_RenderSky = false;

	bool oldWater = g_Renderer.GetWaterManager()->m_RenderWater;
	g_Renderer.GetWaterManager()->m_RenderWater = false;

	g_Renderer.BeginFrame();

	// Find the centre of the interesting region, in the middle of the patch
	// and half way up the model (assuming there is one)
	CVector3D centre;
	CmpPtr<ICmpVisual> cmpVisual(m.Simulation2, m.Entity);
	if (!cmpVisual.null())
		cmpVisual->GetBounds().GetCentre(centre);
	else
		centre.Y = 0.f;
	centre.X = centre.Z = CELL_SIZE * m.Terrain.GetPatchesPerSide()*PATCH_SIZE/2;

	CCamera camera = View::GetView_Actor()->GetCamera();
	camera.m_Orientation.Translate(centre.X, centre.Y, centre.Z);
	camera.UpdateFrustum();
	
	g_Renderer.SetSceneCamera(camera, camera);

	g_Renderer.RenderScene(m);

	// ....

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.f, 1000.f);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	glPushAttrib(GL_ENABLE_BIT);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_CULL_FACE);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	glDisable(GL_ALPHA_TEST);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glEnable(GL_TEXTURE_2D);

	g_ProfileViewer.RenderProfile();

	glPopAttrib();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();

	g_Renderer.EndFrame();

	// Restore the old renderer state
	g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, oldShadows);
	g_Renderer.GetSkyManager()->m_RenderSky = oldSky;
	g_Renderer.GetWaterManager()->m_RenderWater = oldWater;

	ogl_WarnIfError();
}