⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 device.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * 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 + -