Commit 7cb748fe authored by Oliver Stieber's avatar Oliver Stieber Committed by Alexandre Julliard

Makes sure any internal reference counting is passed onto the parent,

any objects referenced by the internal stateblock are released when the stateblock is released (we don't reference count while a stateblock is recording, so recorded stateblocks have no references to clean up).
parent b8d3075d
...@@ -112,7 +112,7 @@ HRESULT WINAPI IDirect3DDevice9Impl_CreateStateBlock(LPDIRECT3DDEVICE9 iface, D3 ...@@ -112,7 +112,7 @@ HRESULT WINAPI IDirect3DDevice9Impl_CreateStateBlock(LPDIRECT3DDEVICE9 iface, D3
object->lpVtbl = &Direct3DStateBlock9_Vtbl; object->lpVtbl = &Direct3DStateBlock9_Vtbl;
object->ref = 1; object->ref = 1;
hrc=IWineD3DDevice_CreateStateBlock(This->WineD3DDevice,Type,&object->wineD3DStateBlock,(IUnknown*)object); hrc=IWineD3DDevice_CreateStateBlock(This->WineD3DDevice, (WINED3DSTATEBLOCKTYPE)Type, &object->wineD3DStateBlock, (IUnknown*)object);
if(hrc != D3D_OK){ if(hrc != D3D_OK){
FIXME("(%p) Call to IWineD3DDevice_CreateStateBlock failed.\n", This); FIXME("(%p) Call to IWineD3DDevice_CreateStateBlock failed.\n", This);
HeapFree(GetProcessHeap(), 0, object); HeapFree(GetProcessHeap(), 0, object);
......
...@@ -49,7 +49,6 @@ ULONG WINAPI IWineD3DBaseTextureImpl_AddRef(IWineD3DBaseTexture *iface) { ...@@ -49,7 +49,6 @@ ULONG WINAPI IWineD3DBaseTextureImpl_AddRef(IWineD3DBaseTexture *iface) {
ULONG ref = InterlockedIncrement(&This->resource.ref); ULONG ref = InterlockedIncrement(&This->resource.ref);
TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1); TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
IUnknown_AddRef(This->resource.parent);
return ref; return ref;
} }
...@@ -60,8 +59,6 @@ ULONG WINAPI IWineD3DBaseTextureImpl_Release(IWineD3DBaseTexture *iface) { ...@@ -60,8 +59,6 @@ ULONG WINAPI IWineD3DBaseTextureImpl_Release(IWineD3DBaseTexture *iface) {
if (ref == 0) { if (ref == 0) {
IWineD3DBaseTextureImpl_CleanUp(iface); IWineD3DBaseTextureImpl_CleanUp(iface);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} else {
IUnknown_Release(This->resource.parent); /* Released the reference to the d3dx object */
} }
return ref; return ref;
} }
......
...@@ -227,7 +227,7 @@ void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD S ...@@ -227,7 +227,7 @@ void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD S
BOOL changeTexture = TRUE; BOOL changeTexture = TRUE;
TRACE("-----------------------> Updating the texture at stage %ld to have new texture state information\n", Stage); TRACE("-----------------------> Updating the texture at stage %ld to have new texture state information\n", Stage);
for (i = 1; i < HIGHEST_TEXTURE_STATE; i++) { for (i = 1; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
BOOL skip = FALSE; BOOL skip = FALSE;
...@@ -283,7 +283,7 @@ void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD S ...@@ -283,7 +283,7 @@ void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD S
} }
/* apply the sampler states to the texture */ /* apply the sampler states to the texture */
for (i = 1; i <= HIGHEST_SAMPLER_STATE;i++) { for (i = 1; i <= WINED3D_HIGHEST_SAMPLER_STATE;i++) {
IWineD3DDevice_SetSamplerState(iface, Stage, i, This->stateBlock->samplerState[Stage][i]); IWineD3DDevice_SetSamplerState(iface, Stage, i, This->stateBlock->samplerState[Stage][i]);
} }
...@@ -419,7 +419,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT ...@@ -419,7 +419,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT
return D3D_OK; return D3D_OK;
} }
HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) { HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DStateBlockImpl *object; IWineD3DStateBlockImpl *object;
...@@ -430,7 +430,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTA ...@@ -430,7 +430,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTA
/* Special case - Used during initialization to produce a placeholder stateblock /* Special case - Used during initialization to produce a placeholder stateblock
so other functions called can update a state block */ so other functions called can update a state block */
if (Type == (D3DSTATEBLOCKTYPE) 0) { if (Type == WINED3DSBT_INIT) {
/* Don't bother increasing the reference count otherwise a device will never /* Don't bother increasing the reference count otherwise a device will never
be freed due to circular dependencies */ be freed due to circular dependencies */
return D3D_OK; return D3D_OK;
...@@ -452,10 +452,10 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTA ...@@ -452,10 +452,10 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTA
TRACE("Updating changed flags appropriate for type %d\n", Type); TRACE("Updating changed flags appropriate for type %d\n", Type);
if (Type == D3DSBT_ALL) { if (Type == WINED3DSBT_ALL) {
TRACE("ALL => Pretend everything has changed\n"); TRACE("ALL => Pretend everything has changed\n");
memset(&object->changed, TRUE, sizeof(This->stateBlock->changed)); memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
} else if (Type == D3DSBT_PIXELSTATE) { } else if (Type == WINED3DSBT_PIXELSTATE) {
memset(&object->changed, FALSE, sizeof(This->stateBlock->changed)); memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
/* TODO: Pixel Shader Constants */ /* TODO: Pixel Shader Constants */
...@@ -475,7 +475,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTA ...@@ -475,7 +475,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTA
object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE; object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
} }
} }
} else if (Type == D3DSBT_VERTEXSTATE) { } else if (Type == WINED3DSBT_VERTEXSTATE) {
memset(&object->changed, FALSE, sizeof(This->stateBlock->changed)); memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
...@@ -1500,8 +1500,17 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT St ...@@ -1500,8 +1500,17 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT St
} }
/* Not recording... */ /* Not recording... */
if (oldSrc != NULL) IWineD3DVertexBuffer_Release(oldSrc); if (pStreamData != NULL) {
if (pStreamData != NULL) IWineD3DVertexBuffer_AddRef(pStreamData); IUnknown *newVertexBufferParent;
/* GetParent will add a ref, so leave it hanging until the vertex buffer is cleared */
IWineD3DVertexBuffer_GetParent(pStreamData, &newVertexBufferParent);
}
if (oldSrc != NULL) {
IUnknown *oldVertexBufferParent;
IWineD3DVertexBuffer_GetParent(oldSrc, &oldVertexBufferParent);
IUnknown_Release(oldVertexBufferParent);
IUnknown_Release(oldVertexBufferParent);
}
return D3D_OK; return D3D_OK;
} }
...@@ -2302,8 +2311,17 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DInde ...@@ -2302,8 +2311,17 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DInde
return D3D_OK; return D3D_OK;
} }
if (oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs); if (pIndexData) {
if (pIndexData) IWineD3DIndexBuffer_AddRef(This->stateBlock->pIndexData); IUnknown *indexBufferParent;
/* Getting the parent causes a addRef... it gets released when the indicies are clear */
IWineD3DIndexBuffer_GetParent(pIndexData, &indexBufferParent);
}
if (oldIdxs) {
IUnknown *indexBufferParent;
IWineD3DIndexBuffer_GetParent(oldIdxs, &indexBufferParent);
IUnknown_Release(indexBufferParent);
IUnknown_Release(indexBufferParent);
}
return D3D_OK; return D3D_OK;
} }
...@@ -3273,8 +3291,8 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD S ...@@ -3273,8 +3291,8 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD S
TRACE("(%p) Sampler(%ld), Type(%d) Value(%ld)\n",This, Sampler ,Type, Value); TRACE("(%p) Sampler(%ld), Type(%d) Value(%ld)\n",This, Sampler ,Type, Value);
if(Sampler > GL_LIMITS(samplers) || Sampler < 0 || Type > HIGHEST_SAMPLER_STATE || Type < 0) { if(Sampler > GL_LIMITS(samplers) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
FIXME("out of range %d %d sampler %ld type %u\n", GL_LIMITS(samplers), HIGHEST_SAMPLER_STATE, Sampler, Type); FIXME("out of range %d %d sampler %ld type %u\n", GL_LIMITS(samplers), WINED3D_HIGHEST_SAMPLER_STATE, Sampler, Type);
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
} }
...@@ -4148,8 +4166,13 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, ...@@ -4148,8 +4166,13 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage,
* and the the application nust set the texture back to null (or have a leaky application), * and the the application nust set the texture back to null (or have a leaky application),
* This means we should pass the refcount upto the parent * This means we should pass the refcount upto the parent
*******************************/ *******************************/
if (NULL != oldTexture) { if (NULL != This->updateStateBlock->textures[Stage]) {
IUnknown *textureParent;
IWineD3DBaseTexture_GetParent(This->updateStateBlock->textures[Stage], (IUnknown **)&textureParent);
/** NOTE: GetParent will increase the ref count for me, I won't clean up untill the texture is set to NULL **/
}
if (NULL != oldTexture) {
IUnknown *textureParent; IUnknown *textureParent;
IWineD3DBaseTexture_GetParent(oldTexture, (IUnknown **)&textureParent); IWineD3DBaseTexture_GetParent(oldTexture, (IUnknown **)&textureParent);
IUnknown_Release(textureParent); IUnknown_Release(textureParent);
...@@ -4159,10 +4182,6 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, ...@@ -4159,10 +4182,6 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage,
if (NULL != pTexture) { if (NULL != pTexture) {
IUnknown *textureParent;
IWineD3DBaseTexture_GetParent(This->updateStateBlock->textures[Stage], (IUnknown **)&textureParent);
/** NOTE: GetParent will increase the ref count for me, I won't clean up untill the texture is set to NULL **/
/* Now setup the texture appropraitly */ /* Now setup the texture appropraitly */
textureType = IWineD3DBaseTexture_GetType(pTexture); textureType = IWineD3DBaseTexture_GetType(pTexture);
...@@ -4327,7 +4346,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSw ...@@ -4327,7 +4346,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSw
object->wineD3DDevice= This; object->wineD3DDevice= This;
/** FIXME: object->parent = parent; **/ /** FIXME: object->parent = parent; **/
object->parent = NULL; object->parent = NULL;
object->blockType = D3DSBT_ALL; object->blockType = WINED3DSBT_ALL;
object->ref = 1; object->ref = 1;
object->lpVtbl = &IWineD3DStateBlock_Vtbl; object->lpVtbl = &IWineD3DStateBlock_Vtbl;
...@@ -4596,7 +4615,12 @@ HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIM ...@@ -4596,7 +4615,12 @@ HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIM
debug_d3dprimitivetype(PrimitiveType), debug_d3dprimitivetype(PrimitiveType),
PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
if (This->stateBlock->streamSource[0] != NULL) IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]); if (This->stateBlock->streamSource[0] != NULL) {
IUnknown *vertexBufferParent;
IWineD3DVertexBuffer_GetParent(This->stateBlock->streamSource[0], &vertexBufferParent);
IUnknown_Release(vertexBufferParent);
IUnknown_Release(vertexBufferParent);
}
/* Note in the following, it's not this type, but that's the purpose of streamIsUP */ /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData; This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
...@@ -4623,14 +4647,28 @@ HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, ...@@ -4623,14 +4647,28 @@ HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
MinVertexIndex, NumVertexIndices, PrimitiveCount, pIndexData, MinVertexIndex, NumVertexIndices, PrimitiveCount, pIndexData,
IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
if (This->stateBlock->streamSource[0] != NULL) IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
if (IndexDataFormat == WINED3DFMT_INDEX16) { if (IndexDataFormat == WINED3DFMT_INDEX16) {
idxStride = 2; idxStride = 2;
} else { } else {
idxStride = 4; idxStride = 4;
} }
if (This->stateBlock->streamSource[0] != NULL) {
IUnknown *vertexBufferParent;
IWineD3DVertexBuffer_GetParent(This->stateBlock->streamSource[0], &vertexBufferParent);
This->stateBlock->streamSource[0] = NULL;
IUnknown_Release(vertexBufferParent);
IUnknown_Release(vertexBufferParent);
}
if (This->stateBlock->pIndexData) {
IUnknown *indexBufferParent;
IWineD3DIndexBuffer_GetParent(This->stateBlock->pIndexData, &indexBufferParent);
This->stateBlock->pIndexData = NULL;
IUnknown_Release(indexBufferParent);
IUnknown_Release(indexBufferParent);
}
/* Note in the following, it's not this type, but that's the purpose of streamIsUP */ /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData; This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
This->stateBlock->streamIsUP = TRUE; This->stateBlock->streamIsUP = TRUE;
...@@ -4641,7 +4679,6 @@ HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, ...@@ -4641,7 +4679,6 @@ HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
/* stream zero settings set to null at end as per the msdn */ /* stream zero settings set to null at end as per the msdn */
This->stateBlock->streamSource[0] = NULL; This->stateBlock->streamSource[0] = NULL;
This->stateBlock->streamStride[0] = 0; This->stateBlock->streamStride[0] = 0;
IWineD3DDevice_SetIndices(iface, NULL, 0);
return D3D_OK; return D3D_OK;
} }
......
...@@ -1572,12 +1572,16 @@ HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, D3DDEV ...@@ -1572,12 +1572,16 @@ HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, D3DDEV
/* FIXME: Use for dx8 code eventually too! */ /* FIXME: Use for dx8 code eventually too! */
/* Deliberately no indentation here, as this if will be removed when dx8 support merged in */ /* Deliberately no indentation here, as this if will be removed when dx8 support merged in */
if (This->dxVersion > 8) { if (This->dxVersion > 8) {
TRACE("(%p) : Creating stateblock\n", This);
/* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */ /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
IWineD3DDevice_CreateStateBlock((IWineD3DDevice *)object, if (D3D_OK != IWineD3DDevice_CreateStateBlock((IWineD3DDevice *)object,
(D3DSTATEBLOCKTYPE) 0, WINED3DSBT_INIT,
(IWineD3DStateBlock **)&object->stateBlock, (IWineD3DStateBlock **)&object->stateBlock,
NULL); /* Note: No parent needed for initial internal stateblock */ NULL) || NULL == object->stateBlock) { /* Note: No parent needed for initial internal stateblock */
WARN("Failed to create stateblock\n");
goto create_device_error;
}
TRACE("(%p) : Created stateblock (%p) \n", This, object->stateBlock);
object->updateStateBlock = object->stateBlock; object->updateStateBlock = object->stateBlock;
IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)object->updateStateBlock); IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)object->updateStateBlock);
/* Setup surfaces for the backbuffer, frontbuffer and depthstencil buffer */ /* Setup surfaces for the backbuffer, frontbuffer and depthstencil buffer */
...@@ -1585,71 +1589,93 @@ HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, D3DDEV ...@@ -1585,71 +1589,93 @@ HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, D3DDEV
/* Setup the implicit swapchain */ /* Setup the implicit swapchain */
TRACE("Creating implicit swapchain\n"); TRACE("Creating implicit swapchain\n");
if (D3D_OK == D3DCB_CreateAdditionalSwapChain((IUnknown *) object->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) && swapchain != NULL) { if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) object->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
WARN("Failed to create implicite swapchain\n");
goto create_device_error;
}
object->renderTarget = swapchain->backBuffer; object->renderTarget = swapchain->backBuffer;
IWineD3DSurface_AddRef(object->renderTarget); IWineD3DSurface_AddRef(object->renderTarget);
/* Depth Stencil support */ /* Depth Stencil support */
object->stencilBufferTarget = object->depthStencilBuffer; object->stencilBufferTarget = object->depthStencilBuffer;
if (NULL != object->stencilBufferTarget) { if (NULL != object->stencilBufferTarget) {
IWineD3DSurface_AddRef(object->stencilBufferTarget); IWineD3DSurface_AddRef(object->stencilBufferTarget);
} }
/* Set up some starting GL setup */ /* Set up some starting GL setup */
ENTER_GL();
/*
* Initialize openGL extension related variables
* with Default values
*/
ENTER_GL(); This->isGLInfoValid = IWineD3DImpl_FillGLCaps(&This->gl_info, swapchain->display);
/* /* Setup all the devices defaults */
* Initialize openGL extension related variables IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)object->stateBlock);
* with Default values
*/
This->isGLInfoValid = IWineD3DImpl_FillGLCaps(&This->gl_info, swapchain->display);
/* Setup all the devices defaults */
IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)object->stateBlock);
#if 0 #if 0
IWineD3DImpl_CheckGraphicsMemory(); IWineD3DImpl_CheckGraphicsMemory();
#endif #endif
LEAVE_GL(); LEAVE_GL();
{ /* Set a default viewport */
D3DVIEWPORT9 vp;
vp.X = 0;
vp.Y = 0;
vp.Width = *(pPresentationParameters->BackBufferWidth);
vp.Height = *(pPresentationParameters->BackBufferHeight);
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
IWineD3DDevice_SetViewport((IWineD3DDevice *)object, &vp);
}
{ /* Set a default viewport */
D3DVIEWPORT9 vp;
vp.X = 0;
vp.Y = 0;
vp.Width = *(pPresentationParameters->BackBufferWidth);
vp.Height = *(pPresentationParameters->BackBufferHeight);
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
IWineD3DDevice_SetViewport((IWineD3DDevice *)object, &vp);
}
/* Initialize the current view state */
object->modelview_valid = 1;
object->proj_valid = 0;
object->view_ident = 1;
object->last_was_rhw = 0;
glGetIntegerv(GL_MAX_LIGHTS, &object->maxConcurrentLights);
TRACE("(%p,%d) All defaults now set up, leaving CreateDevice with %p\n", This, Adapter, object);
/* Initialize the current view state */ /* Clear the screen */
object->modelview_valid = 1; IWineD3DDevice_Clear((IWineD3DDevice *) object, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
object->proj_valid = 0;
object->view_ident = 1;
object->last_was_rhw = 0;
glGetIntegerv(GL_MAX_LIGHTS, &object->maxConcurrentLights);
TRACE("(%p,%d) All defaults now set up, leaving CreateDevice with %p\n", This, Adapter, object);
/* Clear the screen */
IWineD3DDevice_Clear((IWineD3DDevice *) object, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
} else { /* couldn't create swapchain */
IWineD3DStateBlock_Release((IWineD3DStateBlock *)object->updateStateBlock);
object->updateStateBlock = NULL;
IWineD3DStateBlock_Release((IWineD3DStateBlock *)object->stateBlock);
object->stateBlock = NULL;
HeapFree(GetProcessHeap(), 0, object);
*ppReturnedDeviceInterface = NULL;
return D3DERR_INVALIDCALL;
}
} else { /* End of FIXME: remove when dx8 merged in */ } else { /* End of FIXME: remove when dx8 merged in */
FIXME("(%p) Incomplete stub for d3d8\n", This); FIXME("(%p) Incomplete stub for d3d8\n", This);
} }
return D3D_OK; return D3D_OK;
create_device_error:
if (object->updateStateBlock != NULL) {
IWineD3DStateBlock_Release((IWineD3DStateBlock *)object->updateStateBlock);
object->updateStateBlock = NULL;
}
if (object->stateBlock != NULL) {
IWineD3DStateBlock_Release((IWineD3DStateBlock *)object->stateBlock);
object->stateBlock = NULL;
}
if (object->renderTarget != NULL) {
IWineD3DSurface_Release(object->renderTarget);
object->renderTarget = NULL;
}
if (object->stencilBufferTarget != NULL) {
IWineD3DSurface_Release(object->stencilBufferTarget);
object->stencilBufferTarget = NULL;
}
if (object->stencilBufferTarget != NULL) {
IWineD3DSurface_Release(object->stencilBufferTarget);
object->stencilBufferTarget = NULL;
}
if (swapchain != NULL) {
IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
swapchain = NULL;
}
HeapFree(GetProcessHeap(), 0, object);
*ppReturnedDeviceInterface = NULL;
return D3DERR_INVALIDCALL;
} }
HRESULT WINAPI IWineD3DImpl_GetParent(IWineD3D *iface, IUnknown **pParent) { HRESULT WINAPI IWineD3DImpl_GetParent(IWineD3D *iface, IUnknown **pParent) {
......
...@@ -57,6 +57,48 @@ ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) { ...@@ -57,6 +57,48 @@ ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) {
TRACE("(%p) : Releasing from %ld\n", This, refCount + 1); TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
if (!refCount) { if (!refCount) {
/* type 0 represents the primary stateblock, so free all the resources */
if (This->blockType == WINED3DSBT_INIT) {
int counter;
FIXME("Releasing primary stateblock\n");
/* Free any streams still bound */
for (counter = 0 ; counter < MAX_STREAMS ; counter++) {
if (This->streamSource[counter] != NULL) {
IUnknown *vertexBufferParent;
IWineD3DVertexBuffer_GetParent(This->streamSource[counter], &vertexBufferParent);
/* Set to NULL here so that Device_ResourceReleased can give a warning if This->streamSource[counter] == ResourceReleased */
This->streamSource[counter] = NULL;
IUnknown_Release(vertexBufferParent);
IUnknown_Release(vertexBufferParent);
}
}
/* free any index data */
if (This->pIndexData) {
IUnknown *indexBufferParent;
IWineD3DIndexBuffer_GetParent(This->pIndexData, &indexBufferParent);
This->pIndexData = NULL;
TRACE("Releasing index buffer %p p(%p)", This->pIndexData, indexBufferParent);
IUnknown_Release(indexBufferParent);
IUnknown_Release(indexBufferParent);
}
/* NOTE: according to MSDN: The applicaion is responsible for making sure the texture references are cleared down */
for (counter = 0; counter < GL_LIMITS(textures); counter++) {
if (This->textures[counter]) {
IUnknown *textureParent;
IWineD3DBaseTexture_GetParent(This->textures[counter], &textureParent);
/* FIXME: Were not using internal counting properly, so were making up for it here by releasing the object anyway */
IUnknown_Release(textureParent);
/* release our 'internal' hold on the texture */
if(0 != IUnknown_Release(textureParent)) {
TRACE("Texture still referenced by stateblock, applications has leaked Stage = %u Texture = %p Parent = %p\n", counter, This->textures[counter], textureParent);
}
}
}
}
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} }
return refCount; return refCount;
...@@ -242,7 +284,7 @@ HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface){ ...@@ -242,7 +284,7 @@ HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface){
/* FIXME: textures are upto MAX_SAMPLERS for d3d9? */ /* FIXME: textures are upto MAX_SAMPLERS for d3d9? */
/* Texture */ /* Texture */
for (j = 0; j < GL_LIMITS(textures); j++) { for (j = 0; j < GL_LIMITS(textures); j++) {
for (i = 1; i <= HIGHEST_TEXTURE_STATE ; i++) { for (i = 1; i <= WINED3D_HIGHEST_TEXTURE_STATE ; i++) {
if (This->set.textureState[j][i] && (This->textureState[j][i] != if (This->set.textureState[j][i] && (This->textureState[j][i] !=
targetStateBlock->textureState[j][i])) { targetStateBlock->textureState[j][i])) {
...@@ -263,7 +305,7 @@ HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface){ ...@@ -263,7 +305,7 @@ HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface){
/* Samplers */ /* Samplers */
for (j = 0 ; j < GL_LIMITS(samplers); j++){ for (j = 0 ; j < GL_LIMITS(samplers); j++){
for (i = 1; i <= HIGHEST_SAMPLER_STATE ; i++){ /* States are 1 based */ for (i = 1; i <= WINED3D_HIGHEST_SAMPLER_STATE ; i++){ /* States are 1 based */
if (This->set.samplerState[j][i] && (This->samplerState[j][i] != if (This->set.samplerState[j][i] && (This->samplerState[j][i] !=
targetStateBlock->samplerState[j][i])) { targetStateBlock->samplerState[j][i])) {
TRACE("Updating sampler state %d,%d to %ld (was %ld)\n", TRACE("Updating sampler state %d,%d to %ld (was %ld)\n",
...@@ -381,7 +423,7 @@ should really perform a delta so that only the changes get updated*/ ...@@ -381,7 +423,7 @@ should really perform a delta so that only the changes get updated*/
if (This->set.textures[j] && This->changed.textures[j]) { if (This->set.textures[j] && This->changed.textures[j]) {
IWineD3DDevice_SetTexture(pDevice, j, This->textures[j]); IWineD3DDevice_SetTexture(pDevice, j, This->textures[j]);
} }
for (i = 1; i <= HIGHEST_TEXTURE_STATE; i++) { for (i = 1; i <= WINED3D_HIGHEST_TEXTURE_STATE; i++) {
if (This->set.textureState[j][i] && This->changed.textureState[j][i]) { if (This->set.textureState[j][i] && This->changed.textureState[j][i]) {
IWineD3DDevice_SetTextureStageState(pDevice, j, i, This->textureState[j][i]); IWineD3DDevice_SetTextureStageState(pDevice, j, i, This->textureState[j][i]);
} }
...@@ -390,7 +432,7 @@ should really perform a delta so that only the changes get updated*/ ...@@ -390,7 +432,7 @@ should really perform a delta so that only the changes get updated*/
/* Samplers */ /* Samplers */
for (j = 0 ; j < GL_LIMITS(samplers); j++){ for (j = 0 ; j < GL_LIMITS(samplers); j++){
for (i = 1; i <= HIGHEST_SAMPLER_STATE; i++){ for (i = 1; i <= WINED3D_HIGHEST_SAMPLER_STATE; i++){
if (This->set.samplerState[j][i] && This->changed.samplerState[j][i] && This->samplerState[j][i] != 0) { if (This->set.samplerState[j][i] && This->changed.samplerState[j][i] && This->samplerState[j][i] != 0) {
IWineD3DDevice_SetSamplerState(pDevice, j, i, This->samplerState[j][i]); IWineD3DDevice_SetSamplerState(pDevice, j, i, This->samplerState[j][i]);
} }
...@@ -456,10 +498,11 @@ HRESULT WINAPI IWineD3DStateBlockImpl_InitStartupStateBlock(IWineD3DStateBlock* ...@@ -456,10 +498,11 @@ HRESULT WINAPI IWineD3DStateBlockImpl_InitStartupStateBlock(IWineD3DStateBlock*
/* Note this may have a large overhead but it should only be executed /* Note this may have a large overhead but it should only be executed
once, in order to initialize the complete state of the device and once, in order to initialize the complete state of the device and
all opengl equivalents */ all opengl equivalents */
TRACE("-----------------------> Setting up device defaults...\n"); TRACE("(%p) -----------------------> Setting up device defaults... %p \n", This, This->wineD3DDevice);
This->blockType = D3DSBT_ALL; /* TODO: make a special stateblock type for the primary stateblock (it never gets applied so it doesn't need a real type) */
This->blockType = WINED3DSBT_INIT;
/* FIXME: Set some of the defaults for lights, transforms etc */ /* Set some of the defaults for lights, transforms etc */
memcpy(&This->transforms[D3DTS_PROJECTION], &identity, sizeof(identity)); memcpy(&This->transforms[D3DTS_PROJECTION], &identity, sizeof(identity));
memcpy(&This->transforms[D3DTS_VIEW], &identity, sizeof(identity)); memcpy(&This->transforms[D3DTS_VIEW], &identity, sizeof(identity));
for (i = 0; i < 256; ++i) { for (i = 0; i < 256; ++i) {
...@@ -633,7 +676,7 @@ HRESULT WINAPI IWineD3DStateBlockImpl_InitStartupStateBlock(IWineD3DStateBlock* ...@@ -633,7 +676,7 @@ HRESULT WINAPI IWineD3DStateBlockImpl_InitStartupStateBlock(IWineD3DStateBlock*
} }
/* Sampler states*/ /* Sampler states*/
for (i = 0 ; i < MAX_SAMPLERS; i++) { for (i = 0 ; i < GL_LIMITS(samplers); i++) {
TRACE("Setting up default samplers states for sampler %d\n", i); TRACE("Setting up default samplers states for sampler %d\n", i);
This->samplerState[i][WINED3DSAMP_ADDRESSU ] = D3DTADDRESS_WRAP; This->samplerState[i][WINED3DSAMP_ADDRESSU ] = D3DTADDRESS_WRAP;
This->samplerState[i][WINED3DSAMP_ADDRESSV ] = D3DTADDRESS_WRAP; This->samplerState[i][WINED3DSAMP_ADDRESSV ] = D3DTADDRESS_WRAP;
......
...@@ -47,7 +47,6 @@ HRESULT WINAPI IWineD3DVolumeTextureImpl_QueryInterface(IWineD3DVolumeTexture *i ...@@ -47,7 +47,6 @@ HRESULT WINAPI IWineD3DVolumeTextureImpl_QueryInterface(IWineD3DVolumeTexture *i
ULONG WINAPI IWineD3DVolumeTextureImpl_AddRef(IWineD3DVolumeTexture *iface) { ULONG WINAPI IWineD3DVolumeTextureImpl_AddRef(IWineD3DVolumeTexture *iface) {
IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface;
TRACE("(%p) : AddRef increasing from %ld\n", This, This->resource.ref); TRACE("(%p) : AddRef increasing from %ld\n", This, This->resource.ref);
IUnknown_AddRef(This->resource.parent);
return InterlockedIncrement(&This->resource.ref); return InterlockedIncrement(&This->resource.ref);
} }
...@@ -66,8 +65,6 @@ ULONG WINAPI IWineD3DVolumeTextureImpl_Release(IWineD3DVolumeTexture *iface) { ...@@ -66,8 +65,6 @@ ULONG WINAPI IWineD3DVolumeTextureImpl_Release(IWineD3DVolumeTexture *iface) {
} }
IWineD3DBaseTextureImpl_CleanUp((IWineD3DBaseTexture *) iface); IWineD3DBaseTextureImpl_CleanUp((IWineD3DBaseTexture *) iface);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} else {
IUnknown_Release(This->resource.parent); /* Released the reference to the d3dx object */
} }
return ref; return ref;
} }
......
...@@ -170,10 +170,6 @@ extern int num_lock; ...@@ -170,10 +170,6 @@ extern int num_lock;
/* Maximum number of constants provided to the shaders */ /* Maximum number of constants provided to the shaders */
#define HIGHEST_TRANSFORMSTATE 512 #define HIGHEST_TRANSFORMSTATE 512
/* Highest value in D3DTRANSFORMSTATETYPE */ /* Highest value in D3DTRANSFORMSTATETYPE */
#define HIGHEST_TEXTURE_STATE D3DTSS_CONSTANT
/* Highest D3DTSS_ value */
#define HIGHEST_SAMPLER_STATE D3DSAMP_DMAPOFFSET
/* Maximum number of constants provided to the shaders */
#define MAX_CLIPPLANES D3DMAXUSERCLIPPLANES #define MAX_CLIPPLANES D3DMAXUSERCLIPPLANES
#define MAX_PALETTES 256 #define MAX_PALETTES 256
...@@ -781,9 +777,9 @@ typedef struct SAVEDSTATES { ...@@ -781,9 +777,9 @@ typedef struct SAVEDSTATES {
BOOL transform[HIGHEST_TRANSFORMSTATE + 1]; BOOL transform[HIGHEST_TRANSFORMSTATE + 1];
BOOL viewport; BOOL viewport;
BOOL renderState[WINEHIGHEST_RENDER_STATE + 1]; BOOL renderState[WINEHIGHEST_RENDER_STATE + 1];
BOOL textureState[MAX_TEXTURES][HIGHEST_TEXTURE_STATE + 1]; BOOL textureState[MAX_TEXTURES][WINED3D_HIGHEST_TEXTURE_STATE + 1];
BOOL clipplane[MAX_CLIPPLANES]; BOOL clipplane[MAX_CLIPPLANES];
BOOL samplerState[MAX_SAMPLERS][HIGHEST_SAMPLER_STATE + 1]; BOOL samplerState[MAX_SAMPLERS][WINED3D_HIGHEST_SAMPLER_STATE + 1];
BOOL vertexDecl; BOOL vertexDecl;
BOOL pixelShader; BOOL pixelShader;
BOOL vertexShader; BOOL vertexShader;
...@@ -798,7 +794,7 @@ struct IWineD3DStateBlockImpl ...@@ -798,7 +794,7 @@ struct IWineD3DStateBlockImpl
/* IWineD3DStateBlock information */ /* IWineD3DStateBlock information */
IUnknown *parent; IUnknown *parent;
IWineD3DDeviceImpl *wineD3DDevice; IWineD3DDeviceImpl *wineD3DDevice;
D3DSTATEBLOCKTYPE blockType; WINED3DSTATEBLOCKTYPE blockType;
/* Array indicating whether things have been set or changed */ /* Array indicating whether things have been set or changed */
SAVEDSTATES changed; SAVEDSTATES changed;
...@@ -854,9 +850,9 @@ struct IWineD3DStateBlockImpl ...@@ -854,9 +850,9 @@ struct IWineD3DStateBlockImpl
int textureDimensions[MAX_SAMPLERS]; int textureDimensions[MAX_SAMPLERS];
/* Texture State Stage */ /* Texture State Stage */
DWORD textureState[MAX_TEXTURES][HIGHEST_TEXTURE_STATE + 1]; DWORD textureState[MAX_TEXTURES][WINED3D_HIGHEST_TEXTURE_STATE + 1];
/* Sampler States */ /* Sampler States */
DWORD samplerState[MAX_SAMPLERS][HIGHEST_SAMPLER_STATE + 1]; DWORD samplerState[MAX_SAMPLERS][WINED3D_HIGHEST_SAMPLER_STATE + 1];
}; };
......
...@@ -273,7 +273,7 @@ DECLARE_INTERFACE_(IWineD3DDevice,IUnknown) ...@@ -273,7 +273,7 @@ DECLARE_INTERFACE_(IWineD3DDevice,IUnknown)
STDMETHOD(GetParent)(THIS_ IUnknown **pParent) PURE; STDMETHOD(GetParent)(THIS_ IUnknown **pParent) PURE;
STDMETHOD(CreateVertexBuffer)(THIS_ UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,struct IWineD3DVertexBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent) PURE; STDMETHOD(CreateVertexBuffer)(THIS_ UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,struct IWineD3DVertexBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent) PURE;
STDMETHOD(CreateIndexBuffer)(THIS_ UINT Length, DWORD Usage, WINED3DFORMAT Format, D3DPOOL Pool, struct IWineD3DIndexBuffer** ppIndexBuffer, HANDLE* pSharedHandle, IUnknown *parent) PURE; STDMETHOD(CreateIndexBuffer)(THIS_ UINT Length, DWORD Usage, WINED3DFORMAT Format, D3DPOOL Pool, struct IWineD3DIndexBuffer** ppIndexBuffer, HANDLE* pSharedHandle, IUnknown *parent) PURE;
STDMETHOD(CreateStateBlock)(THIS_ D3DSTATEBLOCKTYPE Type, struct IWineD3DStateBlock **ppStateBlock, IUnknown *parent) PURE; STDMETHOD(CreateStateBlock)(THIS_ WINED3DSTATEBLOCKTYPE Type, struct IWineD3DStateBlock **ppStateBlock, IUnknown *parent) PURE;
STDMETHOD(CreateSurface)(THIS_ UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, struct IWineD3DSurface** ppSurface, D3DRESOURCETYPE Type, DWORD Usage, D3DPOOL Pool, D3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, IUnknown *parent) PURE; STDMETHOD(CreateSurface)(THIS_ UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, struct IWineD3DSurface** ppSurface, D3DRESOURCETYPE Type, DWORD Usage, D3DPOOL Pool, D3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, IUnknown *parent) PURE;
STDMETHOD(CreateTexture)(THIS_ UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, D3DPOOL Pool, struct IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent, D3DCB_CREATESURFACEFN pFn) PURE; STDMETHOD(CreateTexture)(THIS_ UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, D3DPOOL Pool, struct IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent, D3DCB_CREATESURFACEFN pFn) PURE;
STDMETHOD(CreateVolumeTexture)(THIS_ UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, D3DPOOL Pool, struct IWineD3DVolumeTexture** ppVolumeTexture, HANDLE* pSharedHandle, IUnknown *parent, D3DCB_CREATEVOLUMEFN pFn) PURE; STDMETHOD(CreateVolumeTexture)(THIS_ UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, D3DPOOL Pool, struct IWineD3DVolumeTexture** ppVolumeTexture, HANDLE* pSharedHandle, IUnknown *parent, D3DCB_CREATEVOLUMEFN pFn) PURE;
......
...@@ -343,9 +343,10 @@ typedef enum _WINED3DSAMPLERSTATETYPE { ...@@ -343,9 +343,10 @@ typedef enum _WINED3DSAMPLERSTATETYPE {
WINED3DSAMP_SRGBTEXTURE = 11, WINED3DSAMP_SRGBTEXTURE = 11,
WINED3DSAMP_ELEMENTINDEX = 12, WINED3DSAMP_ELEMENTINDEX = 12,
WINED3DSAMP_DMAPOFFSET = 13, WINED3DSAMP_DMAPOFFSET = 13,
WINED3DSAMP_FORCE_DWORD = 0x7fffffff, WINED3DSAMP_FORCE_DWORD = 0x7fffffff,
} WINED3DSAMPLERSTATETYPE; } WINED3DSAMPLERSTATETYPE;
#define WINED3D_HIGHEST_SAMPLER_STATE WINED3DSAMP_DMAPOFFSET
typedef enum _WINED3DTEXTURESTAGESTATETYPE { typedef enum _WINED3DTEXTURESTAGESTATETYPE {
WINED3DTSS_COLOROP = 1, WINED3DTSS_COLOROP = 1,
...@@ -371,6 +372,8 @@ typedef enum _WINED3DTEXTURESTAGESTATETYPE { ...@@ -371,6 +372,8 @@ typedef enum _WINED3DTEXTURESTAGESTATETYPE {
WINED3DTSS_FORCE_DWORD = 0x7fffffff WINED3DTSS_FORCE_DWORD = 0x7fffffff
} WINED3DTEXTURESTAGESTATETYPE; } WINED3DTEXTURESTAGESTATETYPE;
#define WINED3D_HIGHEST_TEXTURE_STATE WINED3DTSS_CONSTANT
typedef struct _WINEDD3DRECTPATCH_INFO { typedef struct _WINEDD3DRECTPATCH_INFO {
UINT StartVertexOffsetWidth; UINT StartVertexOffsetWidth;
UINT StartVertexOffsetHeight; UINT StartVertexOffsetHeight;
...@@ -674,6 +677,15 @@ typedef struct _WINED3DCAPS { ...@@ -674,6 +677,15 @@ typedef struct _WINED3DCAPS {
} WINED3DCAPS; } WINED3DCAPS;
typedef enum _WINED3DSTATEBLOCKTYPE {
WINED3DSBT_INIT = 0,
WINED3DSBT_ALL = 1,
WINED3DSBT_PIXELSTATE = 2,
WINED3DSBT_VERTEXSTATE = 3,
WINED3DSBT_FORCE_DWORD = 0xffffffff
} WINED3DSTATEBLOCKTYPE;
typedef struct glDescriptor { typedef struct glDescriptor {
UINT textureName; UINT textureName;
int level; int level;
...@@ -683,4 +695,6 @@ typedef struct glDescriptor { ...@@ -683,4 +695,6 @@ typedef struct glDescriptor {
int/*GLenum*/ glType; int/*GLenum*/ glType;
} glDescriptor; } glDescriptor;
#endif #endif
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