Commit 160258b6 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: Implement mipmap auto generation.

parent 5ab9d85c
......@@ -126,6 +126,73 @@ static void test_cube_textures(IDirect3DDevice9 *device_ptr, DWORD caps)
test_cube_texture_from_pool(device_ptr, caps, D3DPOOL_SCRATCH, FALSE);
}
static void test_mipmap_gen(IDirect3DDevice9 *device)
{
HRESULT hr;
IDirect3D9 *d3d9;
IDirect3DTexture9 *texture;
IDirect3DSurface9 *surface;
DWORD levels;
D3DSURFACE_DESC desc;
int i;
D3DLOCKED_RECT lr;
hr = IDirect3DDevice9_GetDirect3D(device, &d3d9);
ok(hr == D3D_OK, "IDirect3DDevice9_GetDirect3D returned %#x\n", hr);
hr = IDirect3D9_CheckDeviceFormat(d3d9, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
D3DUSAGE_AUTOGENMIPMAP,
D3DRTYPE_TEXTURE, D3DFMT_X8R8G8B8);
if(FAILED(hr))
{
skip("No mipmap generation support\n");
}
hr = IDirect3DDevice9_CreateTexture(device, 64, 64, 0, D3DUSAGE_AUTOGENMIPMAP,
D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, 0);
ok(hr == D3D_OK, "IDirect3DDevice9_CreateTexture failed(%08x)\n", hr);
levels = IDirect3DTexture9_GetLevelCount(texture);
ok(levels == 1, "Got %d levels, expected 1\n", levels);
for(i = 0; i < 6 /* 64 = 2 ^ 6 */; i++)
{
surface = NULL;
hr = IDirect3DTexture9_GetSurfaceLevel(texture, i, &surface);
ok(hr == (i == 0 ? D3D_OK : D3DERR_INVALIDCALL),
"GetSurfaceLevel on level %d returned %#x\n", i, hr);
if(surface) IDirect3DSurface9_Release(surface);
hr = IDirect3DTexture9_GetLevelDesc(texture, i, &desc);
ok(hr == (i == 0 ? D3D_OK : D3DERR_INVALIDCALL),
"GetLevelDesc on level %d returned %#x\n", i, hr);
hr = IDirect3DTexture9_LockRect(texture, i, &lr, NULL, 0);
ok(hr == (i == 0 ? D3D_OK : D3DERR_INVALIDCALL),
"LockRect on level %d returned %#x\n", i, hr);
if(SUCCEEDED(hr))
{
hr = IDirect3DTexture9_UnlockRect(texture, i);
ok(hr == D3D_OK, "Unlock returned %08x\n", hr);
}
}
IDirect3DTexture9_Release(texture);
hr = IDirect3DDevice9_CreateTexture(device, 64, 64, 2 /* levels */, D3DUSAGE_AUTOGENMIPMAP,
D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, 0);
ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_CreateTexture(levels = 2) returned %08x\n", hr);
hr = IDirect3DDevice9_CreateTexture(device, 64, 64, 6 /* levels */, D3DUSAGE_AUTOGENMIPMAP,
D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, 0);
ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_CreateTexture(levels = 6) returned %08x\n", hr);
hr = IDirect3DDevice9_CreateTexture(device, 64, 64, 1 /* levels */, D3DUSAGE_AUTOGENMIPMAP,
D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, 0);
ok(hr == D3D_OK, "IDirect3DDevice9_CreateTexture(levels = 1) returned %08x\n", hr);
levels = IDirect3DTexture9_GetLevelCount(texture);
ok(levels == 1, "Got %d levels, expected 1\n", levels);
IDirect3DTexture9_Release(texture);
}
START_TEST(texture)
{
D3DCAPS9 caps;
......@@ -146,4 +213,5 @@ START_TEST(texture)
test_texture_stage_states(device_ptr, caps.MaxTextureBlendStages);
test_cube_textures(device_ptr, caps.TextureCaps);
test_mipmap_gen(device_ptr);
}
......@@ -2822,6 +2822,115 @@ static void x8l8v8u8_test(IDirect3DDevice9 *device)
IDirect3DTexture9_Release(texture);
}
static void autogen_mipmap_test(IDirect3DDevice9 *device)
{
HRESULT hr;
IDirect3D9 *d3d;
IDirect3DTexture9 *texture = NULL;
IDirect3DSurface9 *surface;
DWORD color;
const RECT r1 = {256, 256, 512, 512};
const RECT r2 = {512, 256, 768, 512};
const RECT r3 = {256, 512, 512, 768};
const RECT r4 = {512, 512, 768, 768};
unsigned int x, y;
D3DLOCKED_RECT lr;
memset(&lr, 0, sizeof(lr));
IDirect3DDevice9_GetDirect3D(device, &d3d);
if(IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE, D3DFMT_X8R8G8B8) != D3D_OK) {
skip("No autogenmipmap support\n");
IDirect3D9_Release(d3d);
return;
}
IDirect3D9_Release(d3d);
hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffff00, 0.0, 0);
ok(hr == D3D_OK, "IDirect3DDevice9_Clear returned %s\n", DXGetErrorString9(hr));
/* Make the mipmap big, so that a smaller mipmap is used
*/
hr = IDirect3DDevice9_CreateTexture(device, 1024, 1024, 0, D3DUSAGE_AUTOGENMIPMAP,
D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, 0);
ok(hr == D3D_OK, "IDirect3DDevice9_CreateTexture returned %s\n", DXGetErrorString9(hr));
hr = IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface);
ok(hr == D3D_OK, "IDirect3DTexture9_GetSurfaceLevel returned %s\n", DXGetErrorString9(hr));
hr = IDirect3DSurface9_LockRect(surface, &lr, NULL, 0);
ok(hr == D3D_OK, "IDirect3DSurface9_LockRect returned %s\n", DXGetErrorString9(hr));
for(y = 0; y < 1024; y++) {
for(x = 0; x < 1024; x++) {
DWORD *dst = (DWORD *) (((BYTE *) lr.pBits) + y * lr.Pitch + x * 4);
POINT pt;
pt.x = x;
pt.y = y;
if(PtInRect(&r1, pt)) {
*dst = 0xffff0000;
} else if(PtInRect(&r2, pt)) {
*dst = 0xff00ff00;
} else if(PtInRect(&r3, pt)) {
*dst = 0xff0000ff;
} else if(PtInRect(&r4, pt)) {
*dst = 0xff000000;
} else {
*dst = 0xffffffff;
}
}
}
hr = IDirect3DSurface9_UnlockRect(surface);
ok(hr == D3D_OK, "IDirect3DSurface9_UnlockRect returned %s\n", DXGetErrorString9(hr));
IDirect3DSurface9_Release(surface);
hr = IDirect3DDevice9_SetTexture(device, 0, (IDirect3DBaseTexture9 *) texture);
ok(hr == D3D_OK, "IDirect3DDevice9_SetTexture returned %s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
ok(hr == D3D_OK, "IDirect3DDevice9_SetSamplerState failed with %s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_BeginScene(device);
ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr));
if(SUCCEEDED(hr)) {
const float quad[] = {
-0.5, -0.5, 0.1, 0.0, 0.0,
-0.5, 0.5, 0.1, 0.0, 1.0,
0.5, -0.5, 0.1, 1.0, 0.0,
0.5, 0.5, 0.1, 1.0, 1.0
};
hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_TEX1);
ok(hr == D3D_OK, "IDirect3DDevice9_SetFVF returned %s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, 5 * sizeof(float));
ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr);
hr = IDirect3DDevice9_EndScene(device);
ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr));
}
hr = IDirect3DDevice9_SetTexture(device, 0, NULL);
ok(hr == D3D_OK, "IDirect3DDevice9_SetTexture returned %s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
ok(hr == D3D_OK, "IDirect3DDevice9_SetSamplerState failed with %s\n", DXGetErrorString9(hr));
IDirect3DTexture9_Release(texture);
hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
ok(hr == D3D_OK, "IDirect3DDevice9_Present failed with %s\n", DXGetErrorString9(hr));
color = getPixelColor(device, 200, 200);
ok(color == 0x00ffffff, "pixel 200/200 has color %08x, expected 0x00ffffff\n", color);
color = getPixelColor(device, 280, 200);
ok(color == 0x000000ff, "pixel 280/200 has color %08x, expected 0x000000ff\n", color);
color = getPixelColor(device, 360, 200);
ok(color == 0x00000000, "pixel 360/200 has color %08x, expected 0x00000000\n", color);
color = getPixelColor(device, 440, 200);
ok(color == 0x00ffffff, "pixel 440/200 has color %08x, expected 0x00ffffff\n", color);
color = getPixelColor(device, 200, 270);
ok(color == 0x00ffffff, "pixel 200/270 has color %08x, expected 0x00ffffff\n", color);
color = getPixelColor(device, 280, 270);
ok(color == 0x00ff0000, "pixel 280/270 has color %08x, expected 0x00ff0000\n", color);
color = getPixelColor(device, 360, 270);
ok(color == 0x0000ff00, "pixel 360/270 has color %08x, expected 0x0000ff00\n", color);
color = getPixelColor(device, 440, 270);
ok(color == 0x00ffffff, "pixel 440/200 has color %08x, expected 0x00ffffff\n", color);
}
START_TEST(visual)
{
IDirect3DDevice9 *device_ptr;
......@@ -2899,6 +3008,7 @@ START_TEST(visual)
release_buffer_test(device_ptr);
float_texture_test(device_ptr);
texture_transform_flags_test(device_ptr);
autogen_mipmap_test(device_ptr);
if (caps.VertexShaderVersion >= D3DVS_VERSION(2, 0))
......
......@@ -161,11 +161,39 @@ DWORD WINAPI IWineD3DBaseTextureImpl_GetLevelCount(IWineD3DBaseTexture *iface) {
HRESULT WINAPI IWineD3DBaseTextureImpl_SetAutoGenFilterType(IWineD3DBaseTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) {
IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
UINT textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface);
if (!(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)) {
TRACE("(%p) : returning invalid call\n", This);
return WINED3DERR_INVALIDCALL;
}
if(This->baseTexture.filterType != FilterType) {
/* What about multithreading? Do we want all the context overhead just to set this value?
* Or should we delay the applying until the texture is used for drawing? For now, apply
* immediately.
*/
ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
ENTER_GL();
glBindTexture(textureDimensions, This->baseTexture.textureName);
checkGLcall("glBindTexture");
switch(FilterType) {
case WINED3DTEXF_NONE:
case WINED3DTEXF_POINT:
glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST);
checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST)");
case WINED3DTEXF_LINEAR:
glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)");
default:
WARN("Unexpected filter type %d, setting to GL_NICEST\n", FilterType);
glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)");
}
LEAVE_GL();
}
This->baseTexture.filterType = FilterType;
TRACE("(%p) :\n", This);
return WINED3D_OK;
......@@ -239,6 +267,16 @@ HRESULT WINAPI IWineD3DBaseTextureImpl_BindTexture(IWineD3DBaseTexture *iface) {
This->baseTexture.states[WINED3DTEXSTA_TSSADDRESSW] = WINED3DTADDRESS_WRAP;
IWineD3DBaseTexture_SetDirty(iface, TRUE);
isNewTexture = TRUE;
if(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP) {
/* This means double binding the texture at creation, but keeps the code simpler all
* in all, and the run-time path free from additional checks
*/
glBindTexture(textureDimensions, This->baseTexture.textureName);
checkGLcall("glBindTexture");
glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)");
}
}
/* Bind the texture */
......
......@@ -882,7 +882,17 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, U
TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
/* Calculate levels for mip mapping */
if (Levels == 0) {
if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
return WINED3DERR_INVALIDCALL;
}
if(Levels > 1) {
WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
return WINED3DERR_INVALIDCALL;
}
object->baseTexture.levels = 1;
} else if (Levels == 0) {
TRACE("calculating levels %d\n", object->baseTexture.levels);
object->baseTexture.levels++;
tmpW = Width;
......@@ -956,7 +966,17 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *ifa
object->depth = Depth;
/* Calculate levels for mip mapping */
if (Levels == 0) {
if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
return WINED3DERR_INVALIDCALL;
}
if(Levels > 1) {
WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
return WINED3DERR_INVALIDCALL;
}
Levels = 1;
} else if (Levels == 0) {
object->baseTexture.levels++;
tmpW = Width;
tmpH = Height;
......@@ -1076,7 +1096,17 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface
object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
/* Calculate levels for mip mapping */
if (Levels == 0) {
if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
return WINED3DERR_INVALIDCALL;
}
if(Levels > 1) {
WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
return WINED3DERR_INVALIDCALL;
}
Levels = 1;
} else if (Levels == 0) {
object->baseTexture.levels++;
tmpW = EdgeLength;
while (tmpW > 1) {
......
......@@ -117,6 +117,9 @@ static const struct {
{"GL_NV_vertex_program1_1", NV_VERTEX_PROGRAM1_1},
{"GL_NV_vertex_program2", NV_VERTEX_PROGRAM2},
{"GL_NV_vertex_program3", NV_VERTEX_PROGRAM3},
/* SGI */
{"GL_SGIS_generate_mipmap", SGIS_GENERATE_MIPMAP},
};
/**********************************************************
......@@ -1477,6 +1480,13 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt
}
}
if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
TRACE_(d3d_caps)("[FAILED] - No mipmap generation support\n");
return WINED3DERR_NOTAVAILABLE;
}
}
/* TODO: Check support against more of the WINED3DUSAGE_QUERY_* constants
* See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/IDirect3D9__CheckDeviceFormat.asp
* and http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/D3DUSAGE_QUERY.asp */
......
......@@ -2833,6 +2833,13 @@ typedef void (WINE_GLAPI * PGLFNGETTEXBUMPPARAMETERFVATIPROC) (GLenum, GLfloat *
typedef int (WINE_GLAPI * PGLXFNGETVIDEOSYNCSGIPROC) (unsigned int *);
typedef int (WINE_GLAPI * PGLXFNWAITVIDEOSYNCSGIPROC) (int, int, unsigned int *);
/* GL_SGIS_generate_mipmap */
#ifndef GLX_SGIS_generate_mipmap
#define GL_GENERATE_MIPMAP_SGIS 0x8191
#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
#define GLX_SGIS_generate_mipmap
#endif
/* GL_VERSION_2_0 */
#ifndef GL_VERSION_2_0
#define GL_VERSION_2_0 1
......@@ -3181,6 +3188,7 @@ typedef enum _GL_SupportedExt {
APPLE_CLIENT_STORAGE,
/* SGI */
SGI_VIDEO_SYNC,
SGIS_GENERATE_MIPMAP,
/* WGL extensions */
WGL_ARB_PBUFFER,
......
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