I tried this patch, everything works like before, can't find any regression in apps like ET: QW, Oblivion, all nvidia D3D SDK tests, 3DMarks and others. Titan Quest looks beter, but there are still some issues in menu, game is not working because of gdi32.dll functionality. I create patch for actual git.
Mirek
Mitchell Wheeler napsal(a):
Hi all,
A week or so ago I tried to get a game working in WINE (Titan Quest), however it seems it really needs a proper DIB engine before it'll be playable.
Anyways, in my attempt to get it working I fixed up some issues w/ "IWineD3DDeviceImpl_UpdateSurface.c" in dlls/wined3d, not entirely sure how you guys do things around here so I thought i'd just post my changes to the function in this mailing list and you can do with it what you want. (Note: it actually has a few different methods of doing one thing, enclosed in macro blocks to toggle between them. Technically the first one should work (i think :) once you guys properly implement surface locking/unlocking, and it's 'simplest', but the last one is the only one that actually works properly (using standard OpenGL calls).
You'll probably have to clean up the code to meet your coding standards / etc, maybe remove the custom byte size calculation of compressed images, and some other things - but the functionality is there... i also fixed the existing code that didn't actually do what it was supposed to, heh.
Regards, Mitchell Wheeler
static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; /** TODO: remove casts to IWineD3DSurfaceImpl * NOTE: move code to surface to accomplish this ****************************************/ IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface; IWineD3DSurfaceImpl *pDestSurface = (IWineD3DSurfaceImpl*)pDestinationSurface; int srcWidth, srcHeight; unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight; WINED3DFORMAT destFormat, srcFormat; int srcLeft, srcTop, destLeft, destTop; WINED3DPOOL 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, *glSrcDescription = NULL; GLenum dummy; int bpp; UINT destByteSize = 0, srcByteSize = 0; int destPixelByteSize = 0, srcPixelByteSize = 0; CONVERT_TYPES convert = NO_CONVERSION;
WINED3DSURFACE_DESC winedesc; TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n",
This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint); memset(&winedesc, 0, sizeof(winedesc)); winedesc.Width = &srcSurfaceWidth; winedesc.Height = &srcSurfaceHeight; winedesc.Pool = &srcPool; winedesc.Format = &srcFormat; winedesc.Size = &srcByteSize;
IWineD3DSurface_GetDesc(pSourceSurface, &winedesc); winedesc.Width = &destSurfaceWidth; winedesc.Height = &destSurfaceHeight; winedesc.Pool = &destPool; winedesc.Format = &destFormat; winedesc.Size = &destByteSize; IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc); if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool !=
WINED3DPOOL_DEFAULT){ WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface); return WINED3DERR_INVALIDCALL; }
/* This call loads the opengl surface directly, instead of copying
the surface to the * destination's sysmem copy. If surface conversion is needed, use BltFast instead to * copy in sysmem and use regular surface loading. */ d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE); if(convert != NO_CONVERSION) { return IWineD3DSurface_BltFast(pDestinationSurface, pDestPoint ? pDestPoint->x : 0, pDestPoint ? pDestPoint->y : 0, pSourceSurface, (RECT *) pSourceRect, 0); }
if (destFormat == WINED3DFMT_UNKNOWN) { TRACE("(%p) : Converting destination surface from
WINED3DFMT_UNKNOWN to the source format\n", This); IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
/* Get the update surface description */ IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc); } ActivateContext(This, This->lastActiveRenderTarget,
CTXUSAGE_RESOURCELOAD);
ENTER_GL(); if (GL_SUPPORT(ARB_MULTITEXTURE)) { GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); checkGLcall("glActiveTextureARB"); } /* Make sure the surface is loaded and up to date */ IWineD3DSurface_PreLoad(pDestinationSurface); IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription); IWineD3DSurface_GetGlDesc(pDestinationSurface, &glSrcDescription); /* this needs to be done in lines if the sourceRect != the
sourceWidth */ srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth; srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight; srcLeft = pSourceRect ? pSourceRect->left : 0; srcTop = pSourceRect ? pSourceRect->top : 0; destLeft = pDestPoint ? pDestPoint->x : 0; destTop = pDestPoint ? pDestPoint->y : 0;
// Calculate the rowOffset / offset values, for copying #define ISDXTFORMAT(format) \ (format == WINED3DFMT_DXT1 || format == WINED3DFMT_DXT2 ||
format == WINED3DFMT_DXT3 || format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5)
// Calculating this for our selves because I don't have faith in how
surface->bytesPerPixel is calculated... destPixelByteSize = destByteSize / (int)(destSurfaceWidth * destSurfaceHeight); srcPixelByteSize = srcByteSize / (int)(srcSurfaceWidth * srcSurfaceHeight);
if(pSourceRect != NULL) { // Irregular surface formats if (destFormat != srcFormat) { FIXME("Can not convert between surface pixel formats..."); // Would require some relatively big code restructuring for
rare occurances (that shouldn't even be supported?)
return WINED3DERR_INVALIDCALL; } // Uniform surface formats else { if(srcWidth != srcSurfaceWidth || srcLeft > 0) { rowoffset = srcSurfaceWidth * srcPixelByteSize; offset += (srcLeft * srcPixelByteSize); } if(srcTop > 0) offset += srcTop * srcSurfaceWidth * srcPixelByteSize; } } /* 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) { // Compressed texture if (ISDXTFORMAT(destFormat)) { if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
#if 0 RECT rect; rect.left = destLeft; rect.top = destTop; rect.right = destLeft + srcWidth; rect.bottom = destTop + srcHeight;
// Lock source/destination regions WINED3DLOCKED_RECT destRect, srcRect; printf("Locking surfaces...\n"); if(
FAILED(IWineD3DSurface_LockRect(pDestinationSurface, &destRect, &rect, 0)) || FAILED(IWineD3DSurface_LockRect(pSourceSurface, &srcRect, pSourceRect, WINED3DLOCK_READONLY))) { // How should we handle this case? Just returning an invalid call for now... return WINED3DERR_INVALIDCALL; }
printf("Surfaces locked, copying contents now... "); if(destFormat == WINED3DFMT_DXT1) { printf("DXT1\n"); //memcpy(destRect.pBits, srcRect.pBits,
srcRect.Pitch * (srcHeight / 2)); //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 2)); memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 8); } else { printf("DXT2-5\n"); //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 4)); memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 16); }
// Unlock source/destination regions IWineD3DSurface_UnlockRect(pSourceSurface); IWineD3DSurface_UnlockRect(pDestinationSurface); printf("Unlocking surfaces...\n");
#elif 0 // Get pointers to the source/destination buffers unsigned char *dest_data = (unsigned char*)IWineD3DSurface_GetData(pDestinationSurface); const unsigned char *src_data = (unsigned char*)IWineD3DSurface_GetData(pSourceSurface);
// Copy subsection of source buffer, in to destination
buffer. unsigned char *dest_ptr = dest_data + offset; const unsigned char *src_ptr = src_data + offset;
size_t i; for(i = 0; i < srcHeight; ++i) { memcpy(dest_ptr, src_ptr, srcWidth * srcPixelByteSize); dest_ptr += rowoffset; src_ptr += rowoffset; } // Upload destination buffer to server GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
glDescription->glFormatInternal, srcWidth, srcHeight, 0, destByteSize, dest_data));
checkGLcall("glCompressedTexImage2DARB");
#elif 1 int blocksize = 16; if(destFormat == WINED3DFMT_DXT1) blocksize = 8;
#define max(a, b) (a > b? a : b) srcHeight = max(srcHeight, 4); srcWidth = max(srcWidth, 4); #undef max int data_size = (srcWidth / 4) * (srcHeight / 4) *
blocksize; int row_size = data_size / srcHeight; int pixel_size = row_size / srcWidth; int stride = srcSurfaceWidth * pixel_size;
unsigned char *temp_buffer = HeapAlloc(GetProcessHeap(),
0, data_size); unsigned char *temp_ptr = temp_buffer;
// Debug info //printf(" > BytesTotal: %i | BytesPerPixel: %i |
RowSize: %i\n", data_size, pixel_size, row_size); //printf(" > Source: %i -> %i, %i -> %i | Dest: %i, %i\n", srcLeft, srcWidth, srcTop, srcHeight, destLeft, destTop); //printf(" > Offset: %i\n", (int)((row_size * srcTop) + srcLeft * pixel_size));
// Get pointers to the source buffer const unsigned char *src_data = (unsigned
char*)IWineD3DSurface_GetData(pSourceSurface); src_data += (stride * srcTop) + srcLeft * pixel_size;
size_t i; for(i = 0; i < srcHeight; ++i) { memcpy(temp_ptr, src_data, row_size); temp_ptr += row_size; src_data += stride; } GL_EXTCALL(glCompressedTexSubImage2DARB( glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormatInternal, data_size, temp_buffer )); //checkGLcall("glCompressedTexSubImage2DARB"); HeapFree(GetProcessHeap(), 0, temp_buffer);
#endif } else { FIXME("TODO: Need to update a DXT compressed texture without hardware support\n"); } } // Uncompressed texture else { /* 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 */ const unsigned char* data =((const 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 { // Compressed texture if (ISDXTFORMAT(destFormat)) { if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { int blocksize = 16; if(destFormat == WINED3DFMT_DXT1) blocksize = 8; #define max(a, b) (a > b? a : b) int data_size = (max(srcWidth, 4) / 4) * (max(srcHeight,
/ 4) * blocksize; #undef max
//printf(" -> S = %i | CompressedTexImage2D(?, %i, %i,
%i, %i, 0, %i, ?)\n", destByteSize, glDescription->level, glDescription->glFormatInternal, srcWidth, srcHeight, data_size);
GL_EXTCALL(glCompressedTexSubImage2DARB(glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight,
glDescription->glFormatInternal, data_size,
IWineD3DSurface_GetData(pSourceSurface)));
checkGLcall("glCompressedTexImage2DARB"); } else { FIXME("TODO: Need to update a DXT compressed texture
without hardware support\n"); } } // Uncompressed Texture else { glTexSubImage2D( glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, IWineD3DSurface_GetData(pSourceSurface) );
checkGLcall("glTexSubImage2D"); } } LEAVE_GL(); ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM; ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE; IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0)); return WINED3D_OK;
}