wined3d: A more detailed occlusion query test and fixes.
diff --git a/dlls/d3d9/tests/query.c b/dlls/d3d9/tests/query.c
index 9f2b5b3..452991d 100644
--- a/dlls/d3d9/tests/query.c
+++ b/dlls/d3d9/tests/query.c
@@ -135,6 +135,117 @@
     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 @@
         }
 
         test_query_support(pD3d, hwnd);
+        test_occlusion_query_states(pD3d, hwnd);
 
         DestroyWindow(hwnd);
         IDirect3D9_Release(pD3d);
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index e5f1c96..622d892 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1259,6 +1259,7 @@
 
     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:
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index 7c91f2e..55c4d00 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -111,13 +111,6 @@
 
     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 @@
 
         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 @@
         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 @@
     {
         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 @@
     {
         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 @@
     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 @@
             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 @@
     {
         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 @@
     {
         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 @@
     {
         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 @@
     {
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
                 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 @@
             break;
     }
 
+    if(dwIssueFlags & WINED3DISSUE_BEGIN) {
+        This->state = QUERY_BUILDING;
+    } else {
+        This->state = QUERY_SIGNALLED;
+    }
+
     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
 }
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 86a6bb8..6806bfe 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1443,6 +1443,15 @@
 
 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 @@
 #endif
 
     /* IWineD3DQuery fields */
+    enum query_state         state;
     WINED3DQUERYTYPE         type;
     /* TODO: Think about using a IUnknown instead of a void* */
     void                     *extendedData;