// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "Direct3DStateBlock8.hpp"
#include "Direct3DDevice8.hpp"
#include "Direct3DBaseTexture8.hpp"
#include "Direct3DVertexBuffer8.hpp"
#include "Direct3DIndexBuffer8.hpp"
#include "Debug.hpp"
#include <assert.h>
namespace D3D8
{
Direct3DStateBlock8::Direct3DStateBlock8(Direct3DDevice8 *device, D3DSTATEBLOCKTYPE type) : device(device), type(type)
{
vertexShaderHandle = 0;
pixelShaderHandle = 0;
indexBuffer = 0;
for(int stream = 0; stream < 16; stream++)
{
streamSource[stream].vertexBuffer = 0;
}
for(int stage = 0; stage < 8; stage++)
{
texture[stage] = 0;
}
clear();
if(type == D3DSBT_PIXELSTATE || type == D3DSBT_ALL)
{
capturePixelRenderStates();
capturePixelTextureStates();
capturePixelShaderStates();
}
if(type == D3DSBT_VERTEXSTATE || type == D3DSBT_ALL)
{
captureVertexRenderStates();
captureVertexTextureStates();
captureLightStates();
captureVertexShaderStates();
}
if(type == D3DSBT_ALL) // Capture remaining states
{
captureTextures();
captureVertexTextures();
captureDisplacementTextures();
captureTexturePalette();
captureVertexStreams();
captureIndexBuffer();
captureViewport();
captureTransforms();
captureTextureTransforms();
captureClippingPlanes();
captureMaterial();
}
}
Direct3DStateBlock8::~Direct3DStateBlock8()
{
clear();
}
long Direct3DStateBlock8::QueryInterface(const IID &iid, void **object)
{
TRACE("");
ASSERT(false); // Internal object
return NOINTERFACE(iid);
}
unsigned long Direct3DStateBlock8::AddRef()
{
TRACE("");
return Unknown::AddRef();
}
unsigned long Direct3DStateBlock8::Release()
{
TRACE("");
return Unknown::Release();
}
long Direct3DStateBlock8::Apply()
{
TRACE("");
if(vertexShaderCaptured)
{
device->SetVertexShader(vertexShaderHandle);
}
if(pixelShaderCaptured)
{
device->SetPixelShader(pixelShaderHandle);
}
if(indexBufferCaptured)
{
device->SetIndices(indexBuffer, baseVertexIndex);
}
for(int state = 0; state < D3DRS_NORMALORDER + 1; state++)
{
if(renderStateCaptured[state])
{
device->SetRenderState((D3DRENDERSTATETYPE)state, renderState[state]);
}
}
for(int stage = 0; stage < 8; stage++)
{
for(int state = 0; state < D3DTSS_RESULTARG + 1; state++)
{
if(textureStageStateCaptured[stage][state])
{
device->SetTextureStageState(stage, (D3DTEXTURESTAGESTATETYPE)state, textureStageState[stage][state]);
}
}
}
for(int stream = 0; stream < 16; stream++)
{
if(streamSourceCaptured[stream])
{
device->SetStreamSource(stream, streamSource[stream].vertexBuffer, streamSource[stream].stride);
}
}
for(int stage = 0; stage < 8; stage++)
{
if(textureCaptured[stage])
{
device->SetTexture(stage, texture[stage]);
}
}
for(int state = 0; state < 512; state++)
{
if(transformCaptured[state])
{
device->SetTransform((D3DTRANSFORMSTATETYPE)state, &transform[state]);
}
}
if(viewportCaptured)
{
device->SetViewport(&viewport);
}
for(int index = 0; index < 6; index++)
{
if(clipPlaneCaptured[index])
{
device->SetClipPlane(index, clipPlane[index]);
}
}
return D3D_OK;
}
long Direct3DStateBlock8::Capture()
{
TRACE("");
if(vertexShaderCaptured)
{
device->GetVertexShader(&vertexShaderHandle);
}
if(pixelShaderCaptured)
{
device->GetPixelShader(&pixelShaderHandle);
}
if(indexBufferCaptured)
{
if(indexBuffer)
{
indexBuffer->Release();
}
device->GetIndices(reinterpret_cast<IDirect3DIndexBuffer8**>(&indexBuffer), &baseVertexIndex);
}
for(int state = 0; state < D3DRS_NORMALORDER + 1; state++)
{
if(renderStateCaptured[state])
{
device->GetRenderState((D3DRENDERSTATETYPE)state, &renderState[state]);
}
}
for(int stage = 0; stage < 8; stage++)
{
for(int state = 0; state < D3DTSS_RESULTARG + 1; state++)
{
if(textureStageStateCaptured[stage][state])
{
device->GetTextureStageState(stage, (D3DTEXTURESTAGESTATETYPE)state, &textureStageState[stage][state]);
}
}
}
for(int stream = 0; stream < 16; stream++)
{
if(streamSourceCaptured[stream])
{
if(streamSource[stream].vertexBuffer)
{
streamSource[stream].vertexBuffer->Release();
}
device->GetStreamSource(stream, reinterpret_cast<IDirect3DVertexBuffer8**>(&streamSource[stream].vertexBuffer), &streamSource[stream].stride);
}
}
for(int stage = 0; stage < 8; stage++)
{
if(textureCaptured[stage])
{
if(texture[stage])
{
texture[stage]->Release();
}
device->GetTexture(stage, reinterpret_cast<IDirect3DBaseTexture8**>(&texture[stage]));
}
}
for(int state = 0; state < 512; state++)
{
if(transformCaptured[state])
{
device->GetTransform((D3DTRANSFORMSTATETYPE)state, &transform[state]);
}
}
if(viewportCaptured)
{
device->GetViewport(&viewport);
}
for(int index = 0; index < 6; index++)
{
if(clipPlaneCaptured[index])
{
device->GetClipPlane(index, clipPlane[index]);
}
}
return D3D_OK;
}
long Direct3DStateBlock8::GetDevice(IDirect3DDevice8 **device)
{
TRACE("");
if(!device)
{
return INVALIDCALL();
}
this->device->AddRef();
*device = this->device;
return D3D_OK;
}
void Direct3DStateBlock8::lightEnable(unsigned long index, int enable)
{
UNIMPLEMENTED();
}
void Direct3DStateBlock8::setClipPlane(unsigned long index, const float *plane)
{
clipPlaneCaptured[index] = true;
clipPlane[index][0] = plane[0];
clipPlane[index][1] = plane[1];
clipPlane[index][2] = plane[2];
clipPlane[index][3] = plane[3];
}
void Direct3DStateBlock8::setCurrentTexturePalette(unsigned int paletteNumber)
{
UNIMPLEMENTED();
}
void Direct3DStateBlock8::setFVF(unsigned long FVF)
{
UNIMPLEMENTED();
}
void Direct3DStateBlock8::setIndices(Direct3DIndexBuffer8 *indexData, unsigned int baseVertexIndex)
{
if(indexData) indexData->AddRef();
indexBufferCaptured = true;
indexBuffer = indexData;
this->baseVertexIndex = baseVertexIndex;
}
void Direct3DStateBlock8::setLight(unsigned long index, const D3DLIGHT8 *light)
{
UNIMPLEMENTED();
}
void Direct3DStateBlock8::setMaterial(const D3DMATERIAL8 *material)
{
UNIMPLEMENTED();
}
void Direct3DStateBlock8::setPixelShader(unsigned long shaderHandle)
{
pixelShaderCaptured = true;
pixelShaderHandle = shaderHandle;
}
void Direct3DStateBlock8::setPixelShaderConstant(unsigned int startRegister, const void *constantData, unsigned int count)
{
UNIMPLEMENTED();
}
void Direct3DStateBlock8::setRenderState(D3DRENDERSTATETYPE state, unsigned long value)
{
renderStateCaptured[state] = true;
renderState[state] = value;
}
void Direct3DStateBlock8::setScissorRect(const RECT *rect)
{
UNIMPLEMENTED();
}
void Direct3DStateBlock8::setStreamSource(unsigned int stream, Direct3DVertexBuffer8 *data, unsigned int stride)
{
if(data) data->AddRef();
streamSourceCaptured[stream] = true;
streamSource[stream].vertexBuffer = data;
streamSource[stream].stride = stride;
}
void Direct3DStateBlock8::setTexture(unsigned long stage, Direct3DBaseTexture8 *texture)
{
if(texture) texture->AddRef();
textureCaptured[stage] = true;
this->texture[stage] = texture;
}
void Direct3DStateBlock8::setTextureStageState(unsigned long stage, D3DTEXTURESTAGESTATETYPE type, unsigned long value)
{
textureStageStateCaptured[stage][type] = true;
textureStageState[stage][type] = value;
}
void Direct3DStateBlock8::setTransform(D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
{
transformCaptured[state] = true;
transform[state] = *matrix;
}
void Direct3DStateBlock8::setViewport(const D3DVIEWPORT8 *viewport)
{
viewportCaptured = true;
this->viewport = *viewport;
}
void Direct3DStateBlock8::setVertexShader(unsigned long shaderHandle)
{
vertexShaderCaptured = true;
vertexShaderHandle = shaderHandle;
}
void Direct3DStateBlock8::setVertexShaderConstant(unsigned int startRegister, const void *constantData, unsigned int count)
{
UNIMPLEMENTED();
}
void Direct3DStateBlock8::clear()
{
// Erase capture flags
vertexShaderCaptured = false;
pixelShaderCaptured = false;
indexBufferCaptured = false;
for(int state = 0; state < D3DRS_NORMALORDER + 1; state++)
{
renderStateCaptured[state] = false;
}
for(int stage = 0; stage < 8; stage++)
{
for(int state = 0; state < D3DTSS_RESULTARG + 1; state++)
{
textureStageStateCaptured[stage][state] = false;
}
}
for(int stream = 0; stream < 16; stream++)
{
streamSourceCaptured[stream] = false;
}
for(int stage = 0; stage < 8; stage++)
{
textureCaptured[stage] = false;
}
for(int state = 0; state < 512; state++)
{
transformCaptured[state] = false;
}
viewportCaptured = false;
for(int index = 0; index < 6; index++)
{
clipPlaneCaptured[index] = false;
}
// Release resources
vertexShaderHandle = 0;
pixelShaderHandle = 0;
if(indexBuffer)
{
indexBuffer->Release();
indexBuffer = 0;
}
for(int stream = 0; stream < 16; stream++)
{
if(streamSource[stream].vertexBuffer)
{
streamSource[stream].vertexBuffer->Release();
streamSource[stream].vertexBuffer = 0;
}
}
for(int stage = 0; stage < 8; stage++)
{
if(texture[stage])
{
texture[stage]->Release();
texture[stage] = 0;
}
}
}
void Direct3DStateBlock8::captureRenderState(D3DRENDERSTATETYPE state)
{
device->GetRenderState(state, &renderState[state]);
renderStateCaptured[state] = true;
}
void Direct3DStateBlock8::captureTextureStageState(unsigned long stage, D3DTEXTURESTAGESTATETYPE type)
{
device->GetTextureStageState(stage, type, &textureStageState[stage][type]);
textureStageStateCaptured[stage][type] = true;
}
void Direct3DStateBlock8::captureTransform(D3DTRANSFORMSTATETYPE state)
{
device->GetTransform(state, &transform[state]);
transformCaptured[state] = true;
}
void Direct3DStateBlock8::capturePixelRenderStates()
{
captureRenderState(D3DRS_ZENABLE);
captureRenderState(D3DRS_FILLMODE);
captureRenderState(D3DRS_SHADEMODE);
captureRenderState(D3DRS_ZWRITEENABLE);
captureRenderState(D3DRS_ALPHATESTENABLE);
captureRenderState(D3DRS_LASTPIXEL);
captureRenderState(D3DRS_SRCBLEND);
captureRenderState(D3DRS_DESTBLEND);
captureRenderState(D3DRS_ZFUNC);
captureRenderState(D3DRS_ALPHAREF);
captureRenderState(D3DRS_ALPHAFUNC);
captureRenderState(D3DRS_DITHERENABLE);
captureRenderState(D3DRS_FOGSTART);
captureRenderState(D3DRS_FOGEND);
captureRenderState(D3DRS_FOGDENSITY);
captureRenderState(D3DRS_ALPHABLENDENABLE);
captureRenderState(D3DRS_ZBIAS);
captureRenderState(D3DRS_STENCILENABLE);
captureRenderState(D3DRS_STENCILFAIL);
captureRenderState(D3DRS_STENCILZFAIL);
captureRenderState(D3DRS_STENCILPASS);
captureRenderState(D3DRS_STENCILFUNC);
captureRenderState(D3DRS_STENCILREF);
captureRenderState(D3DRS_STENCILMASK);
captureRenderState(D3DRS_STENCILWRITEMASK);
captureRenderState(D3DRS_TEXTUREFACTOR);
captureRenderState(D3DRS_WRAP0);
captureRenderState(D3DRS_WRAP1);
captureRenderState(D3DRS_WRAP2);
captureRenderState(D3DRS_WRAP3);
captureRenderState(D3DRS_WRAP4);
captureRenderState(D3DRS_WRAP5);
captureRenderState(D3DRS_WRAP6);
captureRenderState(D3DRS_WRAP7);
captureRenderState(D3DRS_COLORWRITEENABLE);
captureRenderState(D3DRS_BLENDOP);
}
void Direct3DStateBlock8::capturePixelTextureStates()
{
for(int stage = 0; stage < 8; stage++)
{
captureTextureStageState(stage, D3DTSS_COLOROP);
captureTextureStageState(stage, D3DTSS_COLORARG1);
captureTextureStageState(stage, D3DTSS_COLORARG2);
captureTextureStageState(stage, D3DTSS_ALPHAOP);
captureTextureStageState(stage, D3DTSS_ALPHAARG1);
captureTextureStageState(stage, D3DTSS_ALPHAARG2);
captureTextureStageState(stage, D3DTSS_BUMPENVMAT00);
captureTextureStageState(stage, D3DTSS_BUMPENVMAT01);
captureTextureStageState(stage, D3DTSS_BUMPENVMAT10);
captureTextureStageState(stage, D3DTSS_BUMPENVMAT11);
captureTextureStageState(stage, D3DTSS_TEXCOORDINDEX);
captureTextureStageState(stage, D3DTSS_BUMPENVLSCALE);
captureTextureStageState(stage, D3DTSS_BUMPENVLOFFSET);
captureTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS);
captureTextureStageState(stage, D3DTSS_COLORARG0);
captureTextureStageState(stage, D3DTSS_ALPHAARG0);
captureTextureStageState(stage, D3DTSS_RESULTARG);
captureTextureStageState(stage, D3DTSS_ADDRESSU);
captureTextureStageState(stage, D3DTSS_ADDRESSV);
captureTextureStageState(stage, D3DTSS_ADDRESSW);
captureTextureStageState(stage, D3DTSS_BORDERCOLOR);
captureTextureStageState(stage, D3DTSS_MAGFILTER);
captureTextureStageState(stage, D3DTSS_MINFILTER);
captureTextureStageState(stage, D3DTSS_MIPFILTER);
captureTextureStageState(stage, D3DTSS_MIPMAPLODBIAS);
captureTextureStageState(stage, D3DTSS_MAXMIPLEVEL);
captureTextureStageState(stage, D3DTSS_MAXANISOTROPY);
}
}
void Direct3DStateBlock8::capturePixelShaderStates()
{
pixelShaderCaptured = true;
device->GetPixelShader(&pixelShaderHandle);
device->GetPixelShaderConstant(0, pixelShaderConstant, 8);
}
void Direct3DStateBlock8::captureVertexRenderStates()
{
captureRenderState(D3DRS_CULLMODE);
captureRenderState(D3DRS_FOGENABLE);
captureRenderState(D3DRS_FOGCOLOR);
captureRenderState(D3DRS_FOGTABLEMODE);
captureRenderState(D3DRS_FOGSTART);
captureRenderState(D3DRS_FOGEND);
captureRenderState(D3DRS_FOGDENSITY);
captureRenderState(D3DRS_RANGEFOGENABLE);
captureRenderState(D3DRS_AMBIENT);
captureRenderState(D3DRS_COLORVERTEX);
captureRenderState(D3DRS_FOGVERTEXMODE);
captureRenderState(D3DRS_CLIPPING);
captureRenderState(D3DRS_LIGHTING);
captureRenderState(D3DRS_LOCALVIEWER);
captureRenderState(D3DRS_EMISSIVEMATERIALSOURCE);
captureRenderState(D3DRS_AMBIENTMATERIALSOURCE);
captureRenderState(D3DRS_DIFFUSEMATERIALSOURCE);
captureRenderState(D3DRS_SPECULARMATERIALSOURCE);
captureRenderState(D3DRS_VERTEXBLEND);
captureRenderState(D3DRS_CLIPPLANEENABLE);
captureRenderState(D3DRS_POINTSIZE);
captureRenderState(D3DRS_POINTSIZE_MIN);
captureRenderState(D3DRS_POINTSPRITEENABLE);
captureRenderState(D3DRS_POINTSCALEENABLE);
captureRenderState(D3DRS_POINTSCALE_A);
captureRenderState(D3DRS_POINTSCALE_B);
captureRenderState(D3DRS_POINTSCALE_C);
captureRenderState(D3DRS_MULTISAMPLEANTIALIAS);
captureRenderState(D3DRS_MULTISAMPLEMASK);
captureRenderState(D3DRS_PATCHEDGESTYLE);
captureRenderState(D3DRS_POINTSIZE_MAX);
captureRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE);
captureRenderState(D3DRS_TWEENFACTOR);
captureRenderState(D3DRS_NORMALIZENORMALS);
captureRenderState(D3DRS_SPECULARENABLE);
captureRenderState(D3DRS_SHADEMODE);
}
void Direct3DStateBlock8::captureVertexTextureStates()
{
for(int stage = 0; stage < 8; stage++)
{
captureTextureStageState(stage, D3DTSS_TEXCOORDINDEX);
captureTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS);
}
}
void Direct3DStateBlock8::captureLightStates()
{
for(int index = 0; index < 8; index++) // FIXME: Support unlimited index
{
device->GetLight(index, &light[index]);
lightCaptured[index] = true;
}
for(int index = 0; index < 8; index++) // FIXME: Support unlimited index
{
lightEnableState[index] = false;
device->GetLightEnable(index, &lightEnableState[index]);
lightEnableCaptured[index] = true;
}
}
void Direct3DStateBlock8::captureVertexShaderStates()
{
vertexShaderCaptured = true;
device->GetVertexShader(&vertexShaderHandle);
device->GetVertexShaderConstant(0, vertexShaderConstant[0], 256);
}
void Direct3DStateBlock8::captureTextures()
{
for(int sampler = 0; sampler < 8; sampler++)
{
textureCaptured[sampler] = true;
device->GetTexture(sampler, reinterpret_cast<IDirect3DBaseTexture8**>(&texture[sampler]));
if(texture[sampler])
{
texture[sampler]->bind();
texture[sampler]->Release();
}
}
}
void Direct3DStateBlock8::captureVertexTextures()
{
// FIXME
}
void Direct3DStateBlock8::captureDisplacementTextures()
{
// FIXME
}
void Direct3DStateBlock8::captureTexturePalette()
{
paletteNumberCaptured = true;
device->GetCurrentTexturePalette(&paletteNumber);
}
void Direct3DStateBlock8::captureVertexStreams()
{
for(int stream = 0; stream < 16; stream++)
{
streamSourceCaptured[stream] = true;
device->GetStreamSource(stream, reinterpret_cast<IDirect3DVertexBuffer8**>(&streamSource[stream].vertexBuffer), &streamSource[stream].stride);
if(streamSource[stream].vertexBuffer)
{
streamSource[stream].vertexBuffer->bind();
streamSource[stream].vertexBuffer->Release();
}
}
}
void Direct3DStateBlock8::captureIndexBuffer()
{
indexBufferCaptured = true;
device->GetIndices(reinterpret_cast<IDirect3DIndexBuffer8**>(&indexBuffer), &baseVertexIndex);
if(indexBuffer)
{
indexBuffer->bind();
indexBuffer->Release();
}
}
void Direct3DStateBlock8::captureViewport()
{
device->GetViewport(&viewport);
viewportCaptured = true;
}
void Direct3DStateBlock8::captureTransforms()
{
captureTransform(D3DTS_VIEW);
captureTransform(D3DTS_PROJECTION);
captureTransform(D3DTS_WORLD);
}
void Direct3DStateBlock8::captureTextureTransforms()
{
captureTransform(D3DTS_TEXTURE0);
captureTransform(D3DTS_TEXTURE1);
captureTransform(D3DTS_TEXTURE2);
captureTransform(D3DTS_TEXTURE3);
captureTransform(D3DTS_TEXTURE4);
captureTransform(D3DTS_TEXTURE5);
captureTransform(D3DTS_TEXTURE6);
captureTransform(D3DTS_TEXTURE7);
}
void Direct3DStateBlock8::captureClippingPlanes()
{
for(int index = 0; index < 6; index++)
{
device->GetClipPlane(index, (float*)&clipPlane[index]);
clipPlaneCaptured[index] = true;
}
}
void Direct3DStateBlock8::captureMaterial()
{
device->GetMaterial(&material);
materialCaptured = true;
}
}