diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 9990ab996df..5734f21c5a8 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -4618,10 +4618,52 @@ HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, return D3D_OK; } + /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */ HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - - TRACE("(%p) : stub\n", This); + D3DRESOURCETYPE sourceType; + D3DRESOURCETYPE destinationType; + IWineD3DTextureImpl *pDestTexture = (IWineD3DTextureImpl *)pDestinationTexture; + IWineD3DTextureImpl *pSrcTexture = (IWineD3DTextureImpl *)pSourceTexture; + int i; + + sourceType = IWineD3DBaseTexture_GetType(pSourceTexture); + destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture); + if(sourceType != D3DRTYPE_TEXTURE && destinationType != D3DRTYPE_TEXTURE){ + FIXME("(%p) Only D3DRTYPE_TEXTURE to D3DRTYPE_TEXTURE supported\n", This); + return D3DERR_INVALIDCALL; + } + TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture); + + /** TODO: Get rid of the casts to IWineD3DBaseTextureImpl + repalce surfaces[x] with GetSurfaceLevel, or GetCubeMapSurface etc.. + think about moving the code into texture, and adding a member to base texture to occomplish this **/ + + /* Make sure that the destination texture is loaded */ + IWineD3DBaseTexture_PreLoad(pDestinationTexture); + TRACE("Loading source texture\n"); + + if(pSrcTexture->surfaces[0] == NULL || pDestTexture->surfaces[0] == NULL){ + FIXME("(%p) Texture src %p or dest %p has not surface %p %p\n", This, pSrcTexture, pDestTexture, + pSrcTexture->surfaces[0], pDestTexture->surfaces[0]); + } + + if(((IWineD3DSurfaceImpl *)pSrcTexture->surfaces[0])->resource.pool != D3DPOOL_SYSTEMMEM || + ((IWineD3DSurfaceImpl *)pDestTexture->surfaces[0])->resource.pool != D3DPOOL_DEFAULT){ + + FIXME("(%p) source %p must be SYSTEMMEM and dest %p must be DEFAULT\n",This, pSrcTexture, pDestTexture); + return D3DERR_INVALIDCALL; + } + /** TODO: check that both textures have the same number of levels **/ +#if 0 + if(IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) !=IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) + return D3DERR_INVALIDCALL; +#endif + /** TODO: move this code into baseTexture? device should never touch impl*'s **/ + for(i = 0 ; i < IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) ; i++){ + IWineD3DDevice_UpdateSurface(iface, pSrcTexture->surfaces[i], NULL, pDestTexture->surfaces[i], NULL); + } + return D3D_OK; } @@ -4731,10 +4773,169 @@ float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) { HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) { - IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; - FIXME("(%p) : stub\n", This); - return D3D_OK; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + /** TODO: remove casts to IWineD3DSurfaceImpl + * NOTE: move code to surface to accomplish this + ****************************************/ + IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface; + int srcWidth, srcHeight, srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight; + WINED3DFORMAT destFormat, srcFormat; + UINT destSize; + int destLeft, destTop; + D3DPOOL srcPool, destPool; + int offset = 0; + int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */ + glDescriptor *glDescription = NULL; + GLenum textureDimensions = GL_TEXTURE_2D; + IWineD3DBaseTexture *baseTexture; + WINED3DSURFACE_DESC winedesc; + + memset(&winedesc, 0, sizeof(winedesc)); + winedesc.Width = &srcSurfaceWidth; + winedesc.Height = &srcSurfaceHeight; + winedesc.Pool = &srcPool; + winedesc.Format = &srcFormat; + + IWineD3DSurface_GetDesc(pSourceSurface, &winedesc); + + winedesc.Width = &destSurfaceWidth; + winedesc.Height = &destSurfaceHeight; + winedesc.Pool = &destPool; + winedesc.Format = &destFormat; + winedesc.Size = &destSize; + + IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc); + + if(srcPool != D3DPOOL_SYSTEMMEM || destPool != D3DPOOL_DEFAULT){ + FIXME("source %p must be SYSTEMMEM and dest %p must be DEFAULT\n", pSourceSurface, pDestinationSurface); + return D3DERR_INVALIDCALL; + } + /* TODO: change this to use bindTexture */ + /* Make sure the surface is loaded and upto date */ + IWineD3DSurface_PreLoad(pDestinationSurface); + + IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription); + + ENTER_GL(); + + /* this needs to be done in lines if the sourceRect != the sourceWidth */ + srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth; + srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight; + destLeft = pDestPoint ? pDestPoint->x : 0; + destTop = pDestPoint ? pDestPoint->y : 0; + + + /* This function doesn't support compressed textures + the pitch is just bytesPerPixel * width */ + + if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){ + rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel; + offset += pSourceRect->left * pSrcSurface->bytesPerPixel; + /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */ + } + /* TODO DXT formats */ + + if(pSourceRect != NULL && pSourceRect->top != 0){ + offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel; + } + TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n" + ,This + ,glDescription->level + ,destLeft + ,destTop + ,srcWidth + ,srcHeight + ,glDescription->glFormat + ,glDescription->glType + ,IWineD3DSurface_GetData(pSourceSurface) + ); + + /* Sanity check */ + if (IWineD3DSurface_GetData(pSourceSurface) == NULL) { + /* need to lock the surface to get the data */ + FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n"); + } + /* TODO: Cube and volume support */ + if(rowoffset != 0){ + /* not a whole row so we have to do it a line at a time */ + int j; + /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */ + unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset; + + for(j = destTop ; j < (srcHeight + destTop) ; j++){ + + glTexSubImage2D(glDescription->target + ,glDescription->level + ,destLeft + ,j + ,srcWidth + ,1 + ,glDescription->glFormat + ,glDescription->glType + ,data/* could be quicker using */ + ); + data += rowoffset; + } + + } else { /* Full width, so just write out the whole texture */ + + if (WINED3DFMT_DXT1 == destFormat || + WINED3DFMT_DXT3 == destFormat || + WINED3DFMT_DXT5 == destFormat) { + if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { + if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) { + /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */ + FIXME("Updating part of a compressed texture is not supported at the moment\n"); + } if (destFormat != srcFormat) { + FIXME("Updating mixed format compressed texture is not curretly support\n"); + } else { + GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target, + glDescription->level, + glDescription->glFormatInternal, + srcWidth, + srcHeight, + 0, + destSize, + IWineD3DSurface_GetData(pSourceSurface)); + } + } else { + FIXME("Attempting to update a DXT compressed texture without hardware support\n"); + } + + + } else { + /* some applications can not handle odd pitches returned by soft non-power2, so we have + to repack the data from pow2Width/Height to expected Width,Height, this makes the + data returned by GetData non-power2 width/height with hardware non-power2 + pow2Width/height are set to surface width height, repacking isn't needed so it + doesn't matter which function gets called. */ + glTexSubImage2D(glDescription->target + ,glDescription->level + ,destLeft + ,destTop + ,srcWidth + ,srcHeight + ,glDescription->glFormat + ,glDescription->glType + ,IWineD3DSurface_GetData(pSourceSurface) + ); + + } + } + checkGLcall("glTexSubImage2D"); + /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET -> + * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the + * surface bigger than it needs to be hmm.. */ + if (D3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) { + textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture); + IWineD3DBaseTexture_Release(baseTexture); + } + + glDisable(textureDimensions); /* This needs to be managed better.... */ + LEAVE_GL(); + + return D3D_OK; } /* Implementation details at http://developer.nvidia.com/attach/6494 diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 988893cd0fe..483f05be9fa 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -1741,11 +1741,12 @@ void drawPrimitive(IWineD3DDevice *iface, /* And re-upload any dirty textures */ for (i=0; istateBlock->textures[i] != NULL) && - (IWineD3DBaseTexture_GetDirty(This->stateBlock->textures[i]))) - { - /* Load up the texture now */ - IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]); + if (This->stateBlock->textures[i] != NULL) { + + if (IWineD3DBaseTexture_GetDirty(This->stateBlock->textures[i])) { + /* Load up the texture now */ + IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]); + } if (IWineD3DResourceImpl_GetType((IWineD3DResource *)This->stateBlock->textures[i]) == D3DRTYPE_TEXTURE ) { /* TODO: Is this right, as its cast all texture types to texture8... checkme */ IWineD3DSurface *surface; @@ -1753,8 +1754,8 @@ void drawPrimitive(IWineD3DDevice *iface, if (((IWineD3DSurfaceImpl *)surface)->nonpow2) { nonPower2 = TRUE; } - } - } + } + } } /* Now draw the graphics to the screen */ diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 425eb6543fe..af253203542 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -190,15 +190,15 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFAC IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; TRACE("(%p) : copying into %p\n", This, pDesc); - *(pDesc->Format) = This->resource.format; - *(pDesc->Type) = This->resource.resourceType; - *(pDesc->Usage) = This->resource.usage; - *(pDesc->Pool) = This->resource.pool; - *(pDesc->Size) = This->resource.size; /* dx8 only */ - *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType; - *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality; - *(pDesc->Width) = This->currentDesc.Width; - *(pDesc->Height) = This->currentDesc.Height; + if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format; + if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType; + if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage; + if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool; + if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */ + if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType; + if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality; + if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width; + if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height; return D3D_OK; } @@ -406,8 +406,6 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RE *****************************************/ if (!notInContext) { /* Only read the buffer if it's in the current context */ long j; - GLenum format = D3DFmt2GLFmt(myDevice, This->resource.format); - GLenum type = D3DFmt2GLType(myDevice, This->resource.format); #if 0 /* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time, * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game @@ -422,16 +420,16 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RE glReadPixels(0, 0, This->currentDesc.Width, This->currentDesc.Height, - format, - type, + This->glDescription.glFormat, + This->glDescription.glType, (char *)pLockedRect->pBits); }else if (This->lockedRect.left ==0 && This->lockedRect.right == This->currentDesc.Width) { glReadPixels(0, This->lockedRect.top, This->currentDesc.Width, This->currentDesc.Height, - format, - type, + This->glDescription.glFormat, + This->glDescription.glType, (char *)pLockedRect->pBits); } else{ @@ -440,8 +438,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RE This->lockedRect.bottom - j - 1, This->lockedRect.right - This->lockedRect.left, 1, - format, - type, + This->glDescription.glFormat, + This->glDescription.glType, (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top))); } @@ -873,8 +871,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) { This->pow2Width, This->pow2Height, 0/*border*/, - D3DFmt2GLFmt(This->resource.wineD3DDevice, This->resource.format), - D3DFmt2GLType(This->resource.wineD3DDevice, This->resource.format), + This->glDescription.glFormat, + This->glDescription.glType, NULL); checkGLcall("glTexImage2D");