Commit 0e8c13e6 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: A more detailed occlusion query test and fixes.

parent 54fa7129
......@@ -135,6 +135,117 @@ static void test_query_support(IDirect3D9 *pD3d, HWND hwnd)
if(pDevice) IDirect3DDevice9_Release(pDevice);
}
static void test_occlusion_query_states(IDirect3D9 *pD3d, HWND hwnd)
{
HRESULT hr;
IDirect3DDevice9 *pDevice = NULL;
D3DPRESENT_PARAMETERS d3dpp;
D3DDISPLAYMODE d3ddm;
IDirect3DQuery9 *pQuery = NULL;
BYTE *data = NULL;
float point[3] = {0.0, 0.0, 0.0};
unsigned int count = 0;
IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
ok(SUCCEEDED(hr) || hr == D3DERR_NOTAVAILABLE, "Failed to create IDirect3D9Device (%s)\n", DXGetErrorString9(hr));
if (FAILED(hr))
{
skip("Failed to create a d3d device\n");
goto cleanup;
}
hr = IDirect3DDevice9_CreateQuery(pDevice, D3DQUERYTYPE_OCCLUSION, &pQuery);
ok(hr == D3D_OK || D3DERR_NOTAVAILABLE,
"IDirect3DDevice9_CreateQuery returned unexpected return value %s\n", DXGetErrorString9(hr));
if(!pQuery) {
skip("Occlusion queries not supported\n");
goto cleanup;
}
data = HeapAlloc(GetProcessHeap(), 0, IDirect3DQuery9_GetDataSize(pQuery));
hr = IDirect3DQuery9_GetData(pQuery, NULL, 0, D3DGETDATA_FLUSH);
ok(hr == S_OK, "IDirect3DQuery9_GetData(NULL) on a new query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_GetData(pQuery, data, IDirect3DQuery9_GetDataSize(pQuery), D3DGETDATA_FLUSH);
ok(hr == S_OK, "IDirect3DQuery9_GetData on a new query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_Issue(pQuery, D3DISSUE_END);
ok(hr == D3D_OK, "IDirect3DQuery9_Issue(D3DISSUE_END) on a new not yet started query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_Issue(pQuery, D3DISSUE_BEGIN);
ok(hr == D3D_OK, "IDirect3DQuery9_Issue(D3DISSUE_BEGIN) on a new not yet started query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_Issue(pQuery, D3DISSUE_BEGIN);
ok(hr == D3D_OK, "IDirect3DQuery9_Issue(D3DQUERY_BEGIN) on a started query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_GetData(pQuery, NULL, 0, D3DGETDATA_FLUSH);
ok(hr == S_FALSE, "IDirect3DQuery9_GetData(NULL) on a started query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_GetData(pQuery, data, IDirect3DQuery9_GetDataSize(pQuery), D3DGETDATA_FLUSH);
ok(hr == S_FALSE, "IDirect3DQuery9_GetData on a started query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DDevice9_SetFVF(pDevice, D3DFVF_XYZ);
ok(hr == D3D_OK, "IDirect3DDevice9_SetFVF returned %s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_BeginScene(pDevice);
ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr));
if(SUCCEEDED(hr)) {
hr = IDirect3DDevice9_DrawPrimitiveUP(pDevice, D3DPT_POINTLIST, 1, point, 3 * sizeof(float));
ok(hr == D3D_OK, "IDirect3DDevice9_DrawPrimitiveUP returned %s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_EndScene(pDevice);
ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr));
}
hr = IDirect3DQuery9_Issue(pQuery, D3DISSUE_END);
ok(hr == D3D_OK, "IDirect3DQuery9_Issue(D3DISSUE_END) on a started query returned %s\n",
DXGetErrorString9(hr));
hr = S_FALSE;
while(hr == S_FALSE && count < 500) {
hr = IDirect3DQuery9_GetData(pQuery, NULL, 0, D3DGETDATA_FLUSH);
ok(hr == S_OK || hr == S_FALSE, "IDirect3DQuery9_GetData on a ended query returned %s\n",
DXGetErrorString9(hr));
count++;
if(hr == S_FALSE) Sleep(10);
}
ok(hr == S_OK, "Occlusion query did not finish\n");
hr = IDirect3DQuery9_GetData(pQuery, data, IDirect3DQuery9_GetDataSize(pQuery), D3DGETDATA_FLUSH);
ok(hr == S_OK, "IDirect3DQuery9_GetData on a ended query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_GetData(pQuery, data, IDirect3DQuery9_GetDataSize(pQuery), D3DGETDATA_FLUSH);
ok(hr == S_OK, "IDirect3DQuery9_GetData a 2nd time on a ended query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_Issue(pQuery, D3DISSUE_BEGIN);
ok(hr == D3D_OK, "IDirect3DQuery9_Issue(D3DISSUE_BEGIN) on a new not yet started query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_Issue(pQuery, D3DISSUE_END);
ok(hr == D3D_OK, "IDirect3DQuery9_Issue(D3DISSUE_END) on a started query returned %s\n",
DXGetErrorString9(hr));
hr = IDirect3DQuery9_Issue(pQuery, D3DISSUE_END);
ok(hr == D3D_OK, "IDirect3DQuery9_Issue(D3DISSUE_END) on a ended query returned %s\n",
DXGetErrorString9(hr));
cleanup:
HeapFree(GetProcessHeap(), 0, data);
if(pDevice) IDirect3DDevice9_Release(pDevice);
}
START_TEST(query)
{
HMODULE d3d9_handle = LoadLibraryA( "d3d9.dll" );
......@@ -166,6 +277,7 @@ START_TEST(query)
}
test_query_support(pD3d, hwnd);
test_occlusion_query_states(pD3d, hwnd);
DestroyWindow(hwnd);
IDirect3D9_Release(pD3d);
......
......@@ -1259,6 +1259,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINE
D3DCREATEOBJECTINSTANCE(object, Query)
object->type = Type;
object->state = QUERY_CREATED;
/* allocated the 'extended' data based on the type of query requested */
switch(Type){
case WINED3DQUERYTYPE_OCCLUSION:
......
......@@ -111,13 +111,6 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags);
if(dwSize == 0){
/*you can use this method to poll the resource for the query status*/
/*We return success(S_OK) if we support a feature, and faikure(S_FALSE) if we don't, just return success and fluff it for now*/
return S_OK;
}else{
}
switch (This->type){
case WINED3DQUERYTYPE_VCACHE:
......@@ -125,6 +118,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
WINED3DDEVINFO_VCACHE *data = (WINED3DDEVINFO_VCACHE *)pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This);
if(pData == NULL || dwSize == 0) break;
data->Pattern = WINEMAKEFOURCC('C','A','C','H');
data->OptMethod = 0; /*0 get longest strips, 1 optimize vertex cache*/
data->CacheSize = 0; /*cache size, only required if OptMethod == 1*/
......@@ -137,6 +131,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
WINED3DDEVINFO_RESOURCEMANAGER *data = (WINED3DDEVINFO_RESOURCEMANAGER *)pData;
int i;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This);
if(pData == NULL || dwSize == 0) break;
for(i = 0; i < WINED3DRTYPECOUNT; i++){
/*I'm setting the default values to 1 so as to reduce the risk of a div/0 in the caller*/
/* isTextureResident could be used to get some of this infomration */
......@@ -159,6 +154,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
{
WINED3DDEVINFO_VERTEXSTATS *data = (WINED3DDEVINFO_VERTEXSTATS *)pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This);
if(pData == NULL || dwSize == 0) break;
data->NumRenderedTriangles = 1;
data->NumExtraClippingTriangles = 1;
......@@ -168,7 +164,9 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
{
BOOL* data = pData;
WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx;
if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
if(pData == NULL || dwSize == 0) {
break;
} if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
/* See comment in IWineD3DQuery::Issue, event query codeblock */
WARN("Query context not active, reporting GPU idle\n");
*data = TRUE;
......@@ -187,7 +185,17 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
case WINED3DQUERYTYPE_OCCLUSION:
{
DWORD* data = pData;
if (GL_SUPPORT(ARB_OCCLUSION_QUERY) &&
if(This->state == QUERY_CREATED) {
/* D3D allows GetData on a new query, opengl doesn't. So just invent the data outselves */
TRACE("Query wasn't yet started, returning S_OK\n");
res = S_OK;
if(data) *data = 0;
} else if(This->state == QUERY_BUILDING) {
/* Msdn says this returns an error, but our tests show that S_FALSE is returned */
TRACE("Query is building, returning S_FALSE\n");
res = S_FALSE;
} else if (GL_SUPPORT(ARB_OCCLUSION_QUERY) &&
((WineQueryOcclusionData *)This->extendedData)->ctx == This->wineD3DDevice->activeContext &&
This->wineD3DDevice->activeContext->tid == GetCurrentThreadId()) {
GLuint available;
......@@ -199,10 +207,12 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
TRACE("(%p) : available %d.\n", This, available);
if (available) {
GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples));
checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n");
TRACE("(%p) : Returning %d samples.\n", This, samples);
*data = samples;
if(data) {
GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples));
checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n");
TRACE("(%p) : Returning %d samples.\n", This, samples);
*data = samples;
}
res = S_OK;
} else {
res = S_FALSE;
......@@ -218,6 +228,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
{
UINT64* data = pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
if(pData == NULL || dwSize == 0) break;
*data = 1; /*Don't know what this is supposed to be*/
}
break;
......@@ -225,6 +236,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
{
BOOL* data = pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
if(pData == NULL || dwSize == 0) break;
*data = FALSE; /*Don't know what this is supposed to be*/
}
break;
......@@ -232,6 +244,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
{
UINT64* data = pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This);
if(pData == NULL || dwSize == 0) break;
*data = 1; /*Don't know what this is supposed to be*/
}
break;
......@@ -239,6 +252,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
{
WINED3DDEVINFO_PIPELINETIMINGS *data = (WINED3DDEVINFO_PIPELINETIMINGS *)pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
if(pData == NULL || dwSize == 0) break;
data->VertexProcessingTimePercent = 1.0f;
data->PixelProcessingTimePercent = 1.0f;
......@@ -251,6 +265,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
WINED3DDEVINFO_INTERFACETIMINGS *data = (WINED3DDEVINFO_INTERFACETIMINGS *)pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
if(pData == NULL || dwSize == 0) break;
data->WaitingForGPUToUseApplicationResourceTimePercent = 1.0f;
data->WaitingForGPUToAcceptMoreCommandsTimePercent = 1.0f;
data->WaitingForGPUToStayWithinLatencyTimePercent = 1.0f;
......@@ -264,6 +279,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
if(pData == NULL || dwSize == 0) break;
data->MemoryProcessingPercent = 50.0f;
data->ComputationProcessingPercent = 50.0f;
......@@ -274,6 +290,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
if(pData == NULL || dwSize == 0) break;
data->MemoryProcessingPercent = 50.0f;
data->ComputationProcessingPercent = 50.0f;
}
......@@ -283,6 +300,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
WINED3DDEVINFO_BANDWIDTHTIMINGS *data = (WINED3DDEVINFO_BANDWIDTHTIMINGS *)pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
if(pData == NULL || dwSize == 0) break;
data->MaxBandwidthUtilized = 1.0f;
data->FrontEndUploadMemoryUtilizedPercent = 1.0f;
data->VertexRateUtilizedPercent = 1.0f;
......@@ -295,6 +313,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
WINED3DDEVINFO_CACHEUTILIZATION *data = (WINED3DDEVINFO_CACHEUTILIZATION *)pData;
FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
if(pData == NULL || dwSize == 0) break;
data->TextureCacheHitRate = 1.0f;
data->PostTransformVertexCacheHitRate = 1.0f;
}
......@@ -387,13 +406,25 @@ static HRESULT WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIs
if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
WARN("Not the owning context, can't start query\n");
} else {
/* This is allowed according to msdn and our tests. Reset the query and restart */
if (dwIssueFlags & WINED3DISSUE_BEGIN) {
if(This->state == QUERY_BUILDING) {
GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
checkGLcall("glEndQuery()");
}
GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId));
checkGLcall("glBeginQuery()");
}
if (dwIssueFlags & WINED3DISSUE_END) {
GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
checkGLcall("glEndQuery()");
/* Msdn says _END on a non-building occlusion query returns an error, but
* our tests show that it returns OK. But OpenGL doesn't like it, so avoid
* generating an error
*/
if(This->state == QUERY_BUILDING) {
GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
checkGLcall("glEndQuery()");
}
}
}
} else {
......@@ -432,6 +463,12 @@ static HRESULT WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIs
break;
}
if(dwIssueFlags & WINED3DISSUE_BEGIN) {
This->state = QUERY_BUILDING;
} else {
This->state = QUERY_SIGNALLED;
}
return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL. */
}
......
......@@ -1443,6 +1443,15 @@ extern void stateblock_copy(
extern const IWineD3DStateBlockVtbl IWineD3DStateBlock_Vtbl;
/* Direct3D terminology with little modifications. We do not have an issued state
* because only the driver knows about it, but we have a created state because d3d
* allows GetData on a created issue, but opengl doesn't
*/
enum query_state {
QUERY_CREATED,
QUERY_SIGNALLED,
QUERY_BUILDING
};
/*****************************************************************************
* IWineD3DQueryImpl implementation structure (extends IUnknown)
*/
......@@ -1460,6 +1469,7 @@ typedef struct IWineD3DQueryImpl
#endif
/* IWineD3DQuery fields */
enum query_state state;
WINED3DQUERYTYPE type;
/* TODO: Think about using a IUnknown instead of a void* */
void *extendedData;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment