📄 device.c
字号:
/*
* IWineD3DDevice implementation
*
* Copyright 2002 Lionel Ulmer
* Copyright 2002-2005 Jason Edmeades
* Copyright 2003-2004 Raphael Junqueira
* Copyright 2004 Christian Costa
* Copyright 2005 Oliver Stieber
* Copyright 2006-2007 Stefan D鰏inger for CodeWeavers
* Copyright 2006-2007 Henri Verbeet
* Copyright 2007 Andrew Riedi
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdio.h>
#ifdef HAVE_FLOAT_H
# include <float.h>
#endif
#include "wined3d_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
#define GLINFO_LOCATION This->adapter->gl_info
/* Define the default light parameters as specified by MSDN */
const WINED3DLIGHT WINED3D_default_light = {
WINED3DLIGHT_DIRECTIONAL, /* Type */
{ 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
{ 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
{ 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
{ 0.0, 0.0, 0.0 }, /* Position x,y,z */
{ 0.0, 0.0, 1.0 }, /* Direction x,y,z */
0.0, /* Range */
0.0, /* Falloff */
0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
0.0, /* Theta */
0.0 /* Phi */
};
/* static function declarations */
static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
/* helper macros */
#define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
#define D3DCREATEOBJECTINSTANCE(object, type) { \
object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
D3DMEMCHECK(object, pp##type); \
object->lpVtbl = &IWineD3D##type##_Vtbl; \
object->wineD3DDevice = This; \
object->parent = parent; \
object->ref = 1; \
*pp##type = (IWineD3D##type *) object; \
}
#define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
D3DMEMCHECK(object, pp##type); \
object->lpVtbl = &IWineD3D##type##_Vtbl; \
object->parent = parent; \
object->ref = 1; \
object->baseShader.device = (IWineD3DDevice*) This; \
list_init(&object->baseShader.linked_programs); \
*pp##type = (IWineD3D##type *) object; \
}
#define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
D3DMEMCHECK(object, pp##type); \
object->lpVtbl = &IWineD3D##type##_Vtbl; \
object->resource.wineD3DDevice = This; \
object->resource.parent = parent; \
object->resource.resourceType = d3dtype; \
object->resource.ref = 1; \
object->resource.pool = Pool; \
object->resource.format = Format; \
object->resource.usage = Usage; \
object->resource.size = _size; \
list_init(&object->resource.privateData); \
/* Check that we have enough video ram left */ \
if (Pool == WINED3DPOOL_DEFAULT) { \
if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
WARN("Out of 'bogus' video memory\n"); \
HeapFree(GetProcessHeap(), 0, object); \
*pp##type = NULL; \
return WINED3DERR_OUTOFVIDEOMEMORY; \
} \
globalChangeGlRam(_size); \
} \
object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
FIXME("Out of memory!\n"); \
HeapFree(GetProcessHeap(), 0, object); \
*pp##type = NULL; \
return WINED3DERR_OUTOFVIDEOMEMORY; \
} \
*pp##type = (IWineD3D##type *) object; \
IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
TRACE("(%p) : Created resource %p\n", This, object); \
}
#define D3DINITIALIZEBASETEXTURE(_basetexture) { \
_basetexture.levels = Levels; \
_basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
_basetexture.LOD = 0; \
_basetexture.dirty = TRUE; \
_basetexture.is_srgb = FALSE; \
_basetexture.srgb_mode_change_count = 0; \
}
/**********************************************************
* Global variable / Constants follow
**********************************************************/
const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
/**********************************************************
* IUnknown parts follows
**********************************************************/
static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
{
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IWineD3DBase)
|| IsEqualGUID(riid, &IID_IWineD3DDevice)) {
IUnknown_AddRef(iface);
*ppobj = This;
return S_OK;
}
*ppobj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
return refCount;
}
static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
if (!refCount) {
if (This->fbo) {
GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
}
if (This->src_fbo) {
GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
}
if (This->dst_fbo) {
GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
}
if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
/* TODO: Clean up all the surfaces and textures! */
/* NOTE: You must release the parent if the object was created via a callback
** ***************************/
if (This->resources != NULL ) {
FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
dumpResources(This->resources);
}
if(This->contexts) ERR("Context array not freed!\n");
if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
This->haveHardwareCursor = FALSE;
IWineD3D_Release(This->wineD3D);
This->wineD3D = NULL;
HeapFree(GetProcessHeap(), 0, This);
TRACE("Freed device %p\n", This);
This = NULL;
}
return refCount;
}
/**********************************************************
* IWineD3DDevice implementation follows
**********************************************************/
static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
*pParent = This->parent;
IUnknown_AddRef(This->parent);
return WINED3D_OK;
}
static void CreateVBO(IWineD3DVertexBufferImpl *object) {
IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
GLenum error, glUsage;
DWORD vboUsage = object->resource.usage;
if(object->Flags & VBFLAG_VBOCREATEFAIL) {
WARN("Creating a vbo failed once, not trying again\n");
return;
}
TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
/* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
ENTER_GL();
/* Make sure that the gl error is cleared. Do not use checkGLcall
* here because checkGLcall just prints a fixme and continues. However,
* if an error during VBO creation occurs we can fall back to non-vbo operation
* with full functionality(but performance loss)
*/
while(glGetError() != GL_NO_ERROR);
/* Basically the FVF parameter passed to CreateVertexBuffer is no good
* It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
* IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
* look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
* to check if the rhw and color values are in the correct format.
*/
GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
error = glGetError();
if(object->vbo == 0 || error != GL_NO_ERROR) {
WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
goto error;
}
GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
error = glGetError();
if(error != GL_NO_ERROR) {
WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
goto error;
}
/* Don't use static, because dx apps tend to update the buffer
* quite often even if they specify 0 usage. Because we always keep the local copy
* we never read from the vbo and can create a write only opengl buffer.
*/
switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
case WINED3DUSAGE_DYNAMIC:
TRACE("Gl usage = GL_STREAM_DRAW\n");
glUsage = GL_STREAM_DRAW_ARB;
break;
case WINED3DUSAGE_WRITEONLY:
default:
TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
glUsage = GL_DYNAMIC_DRAW_ARB;
break;
}
/* Reserve memory for the buffer. The amount of data won't change
* so we are safe with calling glBufferData once with a NULL ptr and
* calling glBufferSubData on updates
*/
GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
error = glGetError();
if(error != GL_NO_ERROR) {
WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
goto error;
}
LEAVE_GL();
return;
error:
/* Clean up all vbo init, but continue because we can work without a vbo :-) */
FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
object->vbo = 0;
object->Flags |= VBFLAG_VBOCREATEFAIL;
LEAVE_GL();
return;
}
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
IUnknown *parent) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DVertexBufferImpl *object;
WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -