浏览代码

libobs: Add GPU timestamp query support

This change only wraps the functionality. I have rough code to exercise
the the query functionality, but that part is not really clean enough to
submit.
jpark37 6 年之前
父节点
当前提交
0e12d8189c

+ 35 - 0
libobs-d3d11/d3d11-rebuild.cpp

@@ -225,6 +225,29 @@ void gs_swap_chain::Rebuild(ID3D11Device *dev)
 	Init();
 }
 
+void gs_timer::Rebuild(ID3D11Device *dev)
+{
+	D3D11_QUERY_DESC desc;
+	desc.Query = D3D11_QUERY_TIMESTAMP;
+	desc.MiscFlags = 0;
+	HRESULT hr = dev->CreateQuery(&desc, &query_begin);
+	if (FAILED(hr))
+		throw HRError("Failed to create timer", hr);
+	hr = dev->CreateQuery(&desc, &query_end);
+	if (FAILED(hr))
+		throw HRError("Failed to create timer", hr);
+}
+
+void gs_timer_range::Rebuild(ID3D11Device *dev)
+{
+	D3D11_QUERY_DESC desc;
+	desc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
+	desc.MiscFlags = 0;
+	HRESULT hr = dev->CreateQuery(&desc, &query_disjoint);
+	if (FAILED(hr))
+		throw HRError("Failed to create timer", hr);
+}
+
 void SavedBlendState::Rebuild(ID3D11Device *dev)
 {
 	HRESULT hr = dev->CreateBlendState(&bd, &state);
@@ -296,6 +319,12 @@ try {
 		case gs_type::gs_swap_chain:
 			((gs_swap_chain *)obj)->Release();
 			break;
+		case gs_type::gs_timer:
+			((gs_timer *)obj)->Release();
+			break;
+		case gs_type::gs_timer_range:
+			((gs_timer_range *)obj)->Release();
+			break;
 		}
 
 		obj = obj->next;
@@ -372,6 +401,12 @@ try {
 		case gs_type::gs_swap_chain:
 			((gs_swap_chain *)obj)->Rebuild(dev);
 			break;
+		case gs_type::gs_timer:
+			((gs_timer *)obj)->Rebuild(dev);
+			break;
+		case gs_type::gs_timer_range:
+			((gs_timer_range *)obj)->Rebuild(dev);
+			break;
 		}
 
 		obj = obj->next;

+ 110 - 0
libobs-d3d11/d3d11-subsystem.cpp

@@ -1120,6 +1120,34 @@ gs_indexbuffer_t *device_indexbuffer_create(gs_device_t *device,
 	return buffer;
 }
 
+gs_timer_t *device_timer_create(gs_device_t *device)
+{
+	gs_timer *timer = NULL;
+	try {
+		timer = new gs_timer(device);
+	} catch (HRError error) {
+		blog(LOG_ERROR, "device_timer_create (D3D11): %s (%08lX)",
+		     error.str, error.hr);
+		LogD3D11ErrorDetails(error, device);
+	}
+
+	return timer;
+}
+
+gs_timer_range_t *device_timer_range_create(gs_device_t *device)
+{
+	gs_timer_range *range = NULL;
+	try {
+		range = new gs_timer_range(device);
+	} catch (HRError error) {
+		blog(LOG_ERROR, "device_timer_range_create (D3D11): %s (%08lX)",
+		     error.str, error.hr);
+		LogD3D11ErrorDetails(error, device);
+	}
+
+	return range;
+}
+
 enum gs_texture_type device_get_texture_type(const gs_texture_t *texture)
 {
 	return texture->type;
@@ -2232,6 +2260,88 @@ enum gs_index_type gs_indexbuffer_get_type(const gs_indexbuffer_t *indexbuffer)
 	return indexbuffer->type;
 }
 
+void gs_timer_destroy(gs_timer_t *timer)
+{
+	delete timer;
+}
+
+void gs_timer_begin(gs_timer_t *timer)
+{
+	timer->device->context->End(timer->query_begin);
+}
+
+void gs_timer_end(gs_timer_t *timer)
+{
+	timer->device->context->End(timer->query_end);
+}
+
+bool gs_timer_get_data(gs_timer_t *timer, uint64_t *ticks)
+{
+	uint64_t begin, end;
+	HRESULT hr_begin, hr_end;
+	do {
+		hr_begin = timer->device->context->GetData(
+			timer->query_begin, &begin, sizeof(begin), 0);
+	} while (hr_begin == S_FALSE);
+	do {
+		hr_end = timer->device->context->GetData(timer->query_end, &end,
+							 sizeof(end), 0);
+	} while (hr_end == S_FALSE);
+
+	const bool succeeded = SUCCEEDED(hr_begin) && SUCCEEDED(hr_end);
+	if (succeeded)
+		*ticks = end - begin;
+
+	return succeeded;
+}
+
+void gs_timer_range_destroy(gs_timer_range_t *range)
+{
+	delete range;
+}
+
+void gs_timer_range_begin(gs_timer_range_t *range)
+{
+	range->device->context->Begin(range->query_disjoint);
+}
+
+void gs_timer_range_end(gs_timer_range_t *range)
+{
+	range->device->context->End(range->query_disjoint);
+}
+
+bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint,
+			     uint64_t *frequency)
+{
+	D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timestamp_disjoint;
+	HRESULT hr;
+	do {
+		hr = range->device->context->GetData(range->query_disjoint,
+						     &timestamp_disjoint,
+						     sizeof(timestamp_disjoint),
+						     0);
+	} while (hr == S_FALSE);
+
+	const bool succeeded = SUCCEEDED(hr);
+	if (succeeded) {
+		*disjoint = timestamp_disjoint.Disjoint;
+		*frequency = timestamp_disjoint.Frequency;
+	}
+
+	return succeeded;
+}
+
+gs_timer::gs_timer(gs_device_t *device) : gs_obj(device, gs_type::gs_timer)
+{
+	Rebuild(device->device);
+}
+
+gs_timer_range::gs_timer_range(gs_device_t *device)
+	: gs_obj(device, gs_type::gs_timer_range)
+{
+	Rebuild(device->device);
+}
+
 extern "C" EXPORT bool device_gdi_texture_available(void)
 {
 	return true;

+ 27 - 0
libobs-d3d11/d3d11-subsystem.hpp

@@ -292,6 +292,8 @@ enum class gs_type {
 	gs_pixel_shader,
 	gs_duplicator,
 	gs_swap_chain,
+	gs_timer,
+	gs_timer_range,
 };
 
 struct gs_obj {
@@ -373,6 +375,31 @@ struct gs_index_buffer : gs_obj {
 			void *indices, size_t num, uint32_t flags);
 };
 
+struct gs_timer : gs_obj {
+	ComPtr<ID3D11Query> query_begin;
+	ComPtr<ID3D11Query> query_end;
+
+	void Rebuild(ID3D11Device *dev);
+
+	inline void Release()
+	{
+		query_begin.Release();
+		query_end.Release();
+	}
+
+	gs_timer(gs_device_t *device);
+};
+
+struct gs_timer_range : gs_obj {
+	ComPtr<ID3D11Query> query_disjoint;
+
+	void Rebuild(ID3D11Device *dev);
+
+	inline void Release() { query_disjoint.Release(); }
+
+	gs_timer_range(gs_device_t *device);
+};
+
 struct gs_texture : gs_obj {
 	gs_texture_type type;
 	uint32_t levels;

+ 74 - 0
libobs-opengl/gl-subsystem.c

@@ -386,6 +386,27 @@ device_samplerstate_create(gs_device_t *device,
 	return sampler;
 }
 
+gs_timer_t *device_timer_create(gs_device_t *device)
+{
+	struct gs_timer *timer;
+
+	GLuint queries[2];
+	glGenQueries(2, queries);
+	if (!gl_success("glGenQueries"))
+		return NULL;
+
+	timer = bzalloc(sizeof(struct gs_timer));
+	timer->queries[0] = queries[0];
+	timer->queries[1] = queries[1];
+
+	return timer;
+}
+
+gs_timer_range_t *device_timer_range_create(gs_device_t *device)
+{
+	return NULL;
+}
+
 enum gs_texture_type device_get_texture_type(const gs_texture_t *texture)
 {
 	return texture->type;
@@ -1443,3 +1464,56 @@ void gs_samplerstate_destroy(gs_samplerstate_t *samplerstate)
 
 	samplerstate_release(samplerstate);
 }
+
+void gs_timer_destroy(gs_timer_t *timer)
+{
+	if (!timer)
+		return;
+
+	glDeleteQueries(2, timer->queries);
+	gl_success("glDeleteQueries");
+
+	bfree(timer);
+}
+
+void gs_timer_begin(gs_timer_t *timer)
+{
+	glQueryCounter(timer->queries[0], GL_TIMESTAMP);
+	gl_success("glQueryCounter");
+}
+
+void gs_timer_end(gs_timer_t *timer)
+{
+	glQueryCounter(timer->queries[1], GL_TIMESTAMP);
+	gl_success("glQueryCounter");
+}
+
+bool gs_timer_get_data(gs_timer_t *timer, uint64_t *ticks)
+{
+	GLint available = 0;
+	glGetQueryObjectiv(timer->queries[1], GL_QUERY_RESULT_AVAILABLE,
+			   &available);
+
+	GLuint64 begin, end;
+	glGetQueryObjectui64v(timer->queries[0], GL_QUERY_RESULT, &begin);
+	gl_success("glGetQueryObjectui64v");
+	glGetQueryObjectui64v(timer->queries[1], GL_QUERY_RESULT, &end);
+	gl_success("glGetQueryObjectui64v");
+
+	*ticks = end - begin;
+	return true;
+}
+
+void gs_timer_range_destroy(gs_timer_range_t *range) {}
+
+void gs_timer_range_begin(gs_timer_range_t *range) {}
+
+void gs_timer_range_end(gs_timer_range_t *range) {}
+
+bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint,
+			     uint64_t *frequency)
+{
+	*disjoint = false;
+	*frequency = 1000000000;
+	return true;
+}

+ 4 - 0
libobs-opengl/gl-subsystem.h

@@ -396,6 +396,10 @@ static inline void samplerstate_release(gs_samplerstate_t *ss)
 		bfree(ss);
 }
 
+struct gs_timer {
+	GLuint queries[2];
+};
+
 struct gs_shader_param {
 	enum gs_shader_param_type type;
 

+ 2 - 0
libobs/graphics/device-exports.h

@@ -76,6 +76,8 @@ EXPORT gs_indexbuffer_t *device_indexbuffer_create(gs_device_t *device,
 						   enum gs_index_type type,
 						   void *indices, size_t num,
 						   uint32_t flags);
+EXPORT gs_timer_t *device_timer_create(gs_device_t *device);
+EXPORT gs_timer_range_t *device_timer_range_create(gs_device_t *device);
 EXPORT enum gs_texture_type
 device_get_texture_type(const gs_texture_t *texture);
 EXPORT void device_load_vertexbuffer(gs_device_t *device,

+ 11 - 0
libobs/graphics/graphics-imports.c

@@ -65,6 +65,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
 	GRAPHICS_IMPORT(device_pixelshader_create);
 	GRAPHICS_IMPORT(device_vertexbuffer_create);
 	GRAPHICS_IMPORT(device_indexbuffer_create);
+	GRAPHICS_IMPORT(device_timer_create);
+	GRAPHICS_IMPORT(device_timer_range_create);
 	GRAPHICS_IMPORT(device_get_texture_type);
 	GRAPHICS_IMPORT(device_load_vertexbuffer);
 	GRAPHICS_IMPORT(device_load_indexbuffer);
@@ -153,6 +155,15 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
 	GRAPHICS_IMPORT(gs_indexbuffer_get_num_indices);
 	GRAPHICS_IMPORT(gs_indexbuffer_get_type);
 
+	GRAPHICS_IMPORT(gs_timer_destroy);
+	GRAPHICS_IMPORT(gs_timer_begin);
+	GRAPHICS_IMPORT(gs_timer_end);
+	GRAPHICS_IMPORT(gs_timer_get_data);
+	GRAPHICS_IMPORT(gs_timer_range_destroy);
+	GRAPHICS_IMPORT(gs_timer_range_begin);
+	GRAPHICS_IMPORT(gs_timer_range_end);
+	GRAPHICS_IMPORT(gs_timer_range_get_data);
+
 	GRAPHICS_IMPORT(gs_shader_destroy);
 	GRAPHICS_IMPORT(gs_shader_get_num_params);
 	GRAPHICS_IMPORT(gs_shader_get_param_by_idx);

+ 12 - 0
libobs/graphics/graphics-internal.h

@@ -77,6 +77,8 @@ struct gs_exports {
 						       void *indices,
 						       size_t num,
 						       uint32_t flags);
+	gs_timer_t *(*device_timer_create)(gs_device_t *device);
+	gs_timer_range_t *(*device_timer_range_create)(gs_device_t *device);
 	enum gs_texture_type (*device_get_texture_type)(
 		const gs_texture_t *texture);
 	void (*device_load_vertexbuffer)(gs_device_t *device,
@@ -219,6 +221,16 @@ struct gs_exports {
 	enum gs_index_type (*gs_indexbuffer_get_type)(
 		const gs_indexbuffer_t *indexbuffer);
 
+	void (*gs_timer_destroy)(gs_timer_t *timer);
+	void (*gs_timer_begin)(gs_timer_t *timer);
+	void (*gs_timer_end)(gs_timer_t *timer);
+	bool (*gs_timer_get_data)(gs_timer_t *timer, uint64_t *ticks);
+	void (*gs_timer_range_destroy)(gs_timer_range_t *range);
+	bool (*gs_timer_range_begin)(gs_timer_range_t *range);
+	bool (*gs_timer_range_end)(gs_timer_range_t *range);
+	bool (*gs_timer_range_get_data)(gs_timer_range_t *range, bool *disjoint,
+					uint64_t *frequency);
+
 	void (*gs_shader_destroy)(gs_shader_t *shader);
 	int (*gs_shader_get_num_params)(const gs_shader_t *shader);
 	gs_sparam_t *(*gs_shader_get_param_by_idx)(gs_shader_t *shader,

+ 110 - 0
libobs/graphics/graphics.c

@@ -1525,6 +1525,26 @@ gs_indexbuffer_t *gs_indexbuffer_create(enum gs_index_type type, void *indices,
 		graphics->device, type, indices, num, flags);
 }
 
+gs_timer_t *gs_timer_create()
+{
+	graphics_t *graphics = thread_graphics;
+
+	if (!gs_valid("gs_timer_create"))
+		return NULL;
+
+	return graphics->exports.device_timer_create(graphics->device);
+}
+
+gs_timer_range_t *gs_timer_range_create()
+{
+	graphics_t *graphics = thread_graphics;
+
+	if (!gs_valid("gs_timer_range_create"))
+		return NULL;
+
+	return graphics->exports.device_timer_range_create(graphics->device);
+}
+
 enum gs_texture_type gs_get_texture_type(const gs_texture_t *texture)
 {
 	graphics_t *graphics = thread_graphics;
@@ -2543,6 +2563,96 @@ enum gs_index_type gs_indexbuffer_get_type(const gs_indexbuffer_t *indexbuffer)
 	return thread_graphics->exports.gs_indexbuffer_get_type(indexbuffer);
 }
 
+void gs_timer_destroy(gs_timer_t *timer)
+{
+	graphics_t *graphics = thread_graphics;
+
+	if (!gs_valid("gs_timer_destroy"))
+		return;
+	if (!timer)
+		return;
+
+	graphics->exports.gs_timer_destroy(timer);
+}
+
+void gs_timer_begin(gs_timer_t *timer)
+{
+	graphics_t *graphics = thread_graphics;
+
+	if (!gs_valid("gs_timer_begin"))
+		return;
+	if (!timer)
+		return;
+
+	graphics->exports.gs_timer_begin(timer);
+}
+
+void gs_timer_end(gs_timer_t *timer)
+{
+	graphics_t *graphics = thread_graphics;
+
+	if (!gs_valid("gs_timer_end"))
+		return;
+	if (!timer)
+		return;
+
+	graphics->exports.gs_timer_end(timer);
+}
+
+bool gs_timer_get_data(gs_timer_t *timer, uint64_t *ticks)
+{
+	if (!gs_valid_p2("gs_timer_get_data", timer, ticks))
+		return false;
+
+	return thread_graphics->exports.gs_timer_get_data(timer, ticks);
+}
+
+void gs_timer_range_destroy(gs_timer_range_t *range)
+{
+	graphics_t *graphics = thread_graphics;
+
+	if (!gs_valid("gs_timer_range_destroy"))
+		return;
+	if (!range)
+		return;
+
+	graphics->exports.gs_timer_range_destroy(range);
+}
+
+void gs_timer_range_begin(gs_timer_range_t *range)
+{
+	graphics_t *graphics = thread_graphics;
+
+	if (!gs_valid("gs_timer_range_begin"))
+		return;
+	if (!range)
+		return;
+
+	graphics->exports.gs_timer_range_begin(range);
+}
+
+void gs_timer_range_end(gs_timer_range_t *range)
+{
+	graphics_t *graphics = thread_graphics;
+
+	if (!gs_valid("gs_timer_range_end"))
+		return;
+	if (!range)
+		return;
+
+	graphics->exports.gs_timer_range_end(range);
+}
+
+bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint,
+			     uint64_t *frequency)
+{
+	if (!gs_valid_p2("gs_timer_range_get_data", disjoint, frequency))
+		return false;
+
+	return thread_graphics->exports.gs_timer_range_get_data(range, disjoint,
+								frequency);
+}
+
 bool gs_nv12_available(void)
 {
 	if (!gs_valid("gs_nv12_available"))

+ 16 - 0
libobs/graphics/graphics.h

@@ -247,6 +247,7 @@ struct gs_index_buffer;
 struct gs_sampler_state;
 struct gs_shader;
 struct gs_swap_chain;
+struct gs_timer;
 struct gs_texrender;
 struct gs_shader_param;
 struct gs_effect;
@@ -263,6 +264,8 @@ typedef struct gs_vertex_buffer gs_vertbuffer_t;
 typedef struct gs_index_buffer gs_indexbuffer_t;
 typedef struct gs_sampler_state gs_samplerstate_t;
 typedef struct gs_swap_chain gs_swapchain_t;
+typedef struct gs_timer gs_timer_t;
+typedef struct gs_timer_range gs_timer_range_t;
 typedef struct gs_texture_render gs_texrender_t;
 typedef struct gs_shader gs_shader_t;
 typedef struct gs_shader_param gs_sparam_t;
@@ -633,6 +636,9 @@ EXPORT gs_indexbuffer_t *gs_indexbuffer_create(enum gs_index_type type,
 					       void *indices, size_t num,
 					       uint32_t flags);
 
+EXPORT gs_timer_t *gs_timer_create();
+EXPORT gs_timer_range_t *gs_timer_range_create();
+
 EXPORT enum gs_texture_type gs_get_texture_type(const gs_texture_t *texture);
 
 EXPORT void gs_load_vertexbuffer(gs_vertbuffer_t *vertbuffer);
@@ -773,6 +779,16 @@ gs_indexbuffer_get_num_indices(const gs_indexbuffer_t *indexbuffer);
 EXPORT enum gs_index_type
 gs_indexbuffer_get_type(const gs_indexbuffer_t *indexbuffer);
 
+EXPORT void gs_timer_destroy(gs_timer_t *timer);
+EXPORT void gs_timer_begin(gs_timer_t *timer);
+EXPORT void gs_timer_end(gs_timer_t *timer);
+EXPORT bool gs_timer_get_data(gs_timer_t *timer, uint64_t *ticks);
+EXPORT void gs_timer_range_destroy(gs_timer_range_t *timer);
+EXPORT void gs_timer_range_begin(gs_timer_range_t *range);
+EXPORT void gs_timer_range_end(gs_timer_range_t *range);
+EXPORT bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint,
+				    uint64_t *frequency);
+
 EXPORT bool gs_nv12_available(void);
 
 #define GS_USE_DEBUG_MARKERS 0