CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/GPU/Directx9/DrawEngineDX9.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <algorithm>18#include <wrl/client.h>1920#include "Common/Log.h"21#include "Common/MemoryUtil.h"22#include "Common/TimeUtil.h"23#include "Core/MemMap.h"24#include "Core/System.h"25#include "Core/Config.h"26#include "Core/CoreTiming.h"2728#include "Common/GPU/D3D9/D3D9StateCache.h"2930#include "GPU/Math3D.h"31#include "GPU/GPUState.h"32#include "GPU/ge_constants.h"3334#include "GPU/Common/SplineCommon.h"35#include "GPU/Common/TransformCommon.h"36#include "GPU/Common/VertexDecoderCommon.h"37#include "GPU/Common/SoftwareTransformCommon.h"38#include "GPU/Debugger/Debugger.h"39#include "GPU/Directx9/TextureCacheDX9.h"40#include "GPU/Directx9/DrawEngineDX9.h"41#include "GPU/Directx9/ShaderManagerDX9.h"42#include "GPU/Directx9/GPU_DX9.h"4344using Microsoft::WRL::ComPtr;4546static const D3DPRIMITIVETYPE d3d_prim[8] = {47// Points, which are expanded to triangles.48D3DPT_TRIANGLELIST,49// Lines and line strips, which are also expanded to triangles.50D3DPT_TRIANGLELIST,51D3DPT_TRIANGLELIST,52D3DPT_TRIANGLELIST,53D3DPT_TRIANGLESTRIP,54D3DPT_TRIANGLEFAN,55// Rectangles, which are expanded to triangles.56D3DPT_TRIANGLELIST,57};5859static const int D3DPRIMITIVEVERTEXCOUNT[8][2] = {60{0, 0}, // invalid61{1, 0}, // 1 = D3DPT_POINTLIST,62{2, 0}, // 2 = D3DPT_LINELIST,63{2, 1}, // 3 = D3DPT_LINESTRIP,64{3, 0}, // 4 = D3DPT_TRIANGLELIST,65{1, 2}, // 5 = D3DPT_TRIANGLESTRIP,66{1, 2}, // 6 = D3DPT_TRIANGLEFAN,67};6869inline int D3DPrimCount(D3DPRIMITIVETYPE prim, int size) {70return (size / D3DPRIMITIVEVERTEXCOUNT[prim][0]) - D3DPRIMITIVEVERTEXCOUNT[prim][1];71}7273enum {74TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex)75};7677static const D3DVERTEXELEMENT9 TransformedVertexElements[] = {78{ 0, offsetof(TransformedVertex, pos), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },79{ 0, offsetof(TransformedVertex, uv), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },80{ 0, offsetof(TransformedVertex, color0), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },81{ 0, offsetof(TransformedVertex, color1), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 },82{ 0, offsetof(TransformedVertex, fog), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },83D3DDECL_END()84};8586DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : draw_(draw), vertexDeclMap_(64) {87device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE);88decOptions_.expandAllWeightsToFloat = true;89decOptions_.expand8BitNormalsToFloat = true;9091indexGen.Setup(decIndex_);9293InitDeviceObjects();9495tessDataTransferDX9 = new TessellationDataTransferDX9();96tessDataTransfer = tessDataTransferDX9;9798device_->CreateVertexDeclaration(TransformedVertexElements, &transformedVertexDecl_);99}100101DrawEngineDX9::~DrawEngineDX9() {102DestroyDeviceObjects();103vertexDeclMap_.Clear();104delete tessDataTransferDX9;105}106107void DrawEngineDX9::InitDeviceObjects() {108draw_->SetInvalidationCallback(std::bind(&DrawEngineDX9::Invalidate, this, std::placeholders::_1));109}110111void DrawEngineDX9::DestroyDeviceObjects() {112if (draw_) {113draw_->SetInvalidationCallback(InvalidationCallback());114}115ClearTrackedVertexArrays();116}117118struct DeclTypeInfo {119u32 type;120const char * name;121};122123static const DeclTypeInfo VComp[] = {124{ 0, "NULL" }, // DEC_NONE,125{ D3DDECLTYPE_FLOAT1, "D3DDECLTYPE_FLOAT1 " }, // DEC_FLOAT_1,126{ D3DDECLTYPE_FLOAT2, "D3DDECLTYPE_FLOAT2 " }, // DEC_FLOAT_2,127{ D3DDECLTYPE_FLOAT3, "D3DDECLTYPE_FLOAT3 " }, // DEC_FLOAT_3,128{ D3DDECLTYPE_FLOAT4, "D3DDECLTYPE_FLOAT4 " }, // DEC_FLOAT_4,129130{ 0, "UNUSED" }, // DEC_S8_3,131132{ D3DDECLTYPE_SHORT4N, "D3DDECLTYPE_SHORT4N " }, // DEC_S16_3,133{ D3DDECLTYPE_UBYTE4N, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_1,134{ D3DDECLTYPE_UBYTE4N, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_2,135{ D3DDECLTYPE_UBYTE4N, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_3,136{ D3DDECLTYPE_UBYTE4N, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_4,137{0, "UNUSED_DEC_U16_1" }, // DEC_U16_1,138{0, "UNUSED_DEC_U16_2" }, // DEC_U16_2,139{D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3,140{D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4,141};142143static void VertexAttribSetup(D3DVERTEXELEMENT9 * VertexElement, u8 fmt, u8 offset, u8 usage, u8 usage_index = 0) {144memset(VertexElement, 0, sizeof(D3DVERTEXELEMENT9));145VertexElement->Offset = offset;146VertexElement->Type = VComp[fmt].type;147VertexElement->Usage = usage;148VertexElement->UsageIndex = usage_index;149}150151HRESULT DrawEngineDX9::SetupDecFmtForDraw(const DecVtxFormat &decFmt, u32 pspFmt, IDirect3DVertexDeclaration9 **ppVertextDeclaration) {152ComPtr<IDirect3DVertexDeclaration9> vertexDeclCached;153if (vertexDeclMap_.Get(pspFmt, &vertexDeclCached)) {154*ppVertextDeclaration = vertexDeclCached.Detach();155return S_OK;156} else {157D3DVERTEXELEMENT9 VertexElements[8];158D3DVERTEXELEMENT9 *VertexElement = &VertexElements[0];159160// Vertices Elements orders161// WEIGHT162if (decFmt.w0fmt != 0) {163VertexAttribSetup(VertexElement, decFmt.w0fmt, decFmt.w0off, D3DDECLUSAGE_TEXCOORD, 1);164VertexElement++;165}166167if (decFmt.w1fmt != 0) {168VertexAttribSetup(VertexElement, decFmt.w1fmt, decFmt.w1off, D3DDECLUSAGE_TEXCOORD, 2);169VertexElement++;170}171172// TC173if (decFmt.uvfmt != 0) {174VertexAttribSetup(VertexElement, decFmt.uvfmt, decFmt.uvoff, D3DDECLUSAGE_TEXCOORD, 0);175VertexElement++;176}177178// COLOR179if (decFmt.c0fmt != 0) {180VertexAttribSetup(VertexElement, decFmt.c0fmt, decFmt.c0off, D3DDECLUSAGE_COLOR, 0);181VertexElement++;182}183// Never used ?184if (decFmt.c1fmt != 0) {185VertexAttribSetup(VertexElement, decFmt.c1fmt, decFmt.c1off, D3DDECLUSAGE_COLOR, 1);186VertexElement++;187}188189// NORMAL190if (decFmt.nrmfmt != 0) {191VertexAttribSetup(VertexElement, decFmt.nrmfmt, decFmt.nrmoff, D3DDECLUSAGE_NORMAL, 0);192VertexElement++;193}194195// POSITION196// Always197VertexAttribSetup(VertexElement, DecVtxFormat::PosFmt(), decFmt.posoff, D3DDECLUSAGE_POSITION, 0);198VertexElement++;199200// End201D3DVERTEXELEMENT9 end = D3DDECL_END();202memcpy(VertexElement, &end, sizeof(D3DVERTEXELEMENT9));203204// Create declaration205ComPtr<IDirect3DVertexDeclaration9> pHardwareVertexDecl;206HRESULT hr = device_->CreateVertexDeclaration( VertexElements, &pHardwareVertexDecl );207if (FAILED(hr)) {208ERROR_LOG(Log::G3D, "Failed to create vertex declaration!");209}210211// Add it to map212vertexDeclMap_.Insert(pspFmt, pHardwareVertexDecl);213*ppVertextDeclaration = pHardwareVertexDecl.Detach();214return hr;215}216}217218static uint32_t SwapRB(uint32_t c) {219return (c & 0xFF00FF00) | ((c >> 16) & 0xFF) | ((c << 16) & 0xFF0000);220}221222void DrawEngineDX9::BeginFrame() {223lastRenderStepId_ = -1;224}225226// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.227void DrawEngineDX9::Invalidate(InvalidationCallbackFlags flags) {228if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) {229gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);230}231}232233// The inline wrapper in the header checks for numDrawCalls_ == 0234void DrawEngineDX9::DoFlush() {235bool textureNeedsApply = false;236if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {237textureCache_->SetTexture();238gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);239textureNeedsApply = true;240} else if (gstate.getTextureAddress(0) == (gstate.getFrameBufRawAddress() | 0x04000000)) {241// This catches the case of clearing a texture. (#10957)242gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);243}244245GEPrimitiveType prim = prevPrim_;246247// Always use software for flat shading to fix the provoking index.248bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;249bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);250251if (useHWTransform) {252LPDIRECT3DVERTEXBUFFER9 vb_ = nullptr;253LPDIRECT3DINDEXBUFFER9 ib_ = nullptr;254255int vertexCount;256int maxIndex;257bool useElements;258DecodeVerts(decoded_);259DecodeIndsAndGetData(&prim, &vertexCount, &maxIndex, &useElements, false);260gpuStats.numUncachedVertsDrawn += vertexCount;261262_dbg_assert_((int)prim > 0);263264bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;265if (gstate.isModeThrough()) {266gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);267} else {268gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);269}270271if (textureNeedsApply) {272textureCache_->ApplyTexture();273}274275ApplyDrawState(prim);276ApplyDrawStateLate();277278VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_);279ComPtr<IDirect3DVertexDeclaration9> pHardwareVertexDecl;280SetupDecFmtForDraw(dec_->GetDecVtxFmt(), dec_->VertexType(), &pHardwareVertexDecl);281282if (pHardwareVertexDecl) {283device_->SetVertexDeclaration(pHardwareVertexDecl.Get());284if (vb_ == NULL) {285if (useElements) {286device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, numDecodedVerts_, D3DPrimCount(d3d_prim[prim], vertexCount), decIndex_, D3DFMT_INDEX16, decoded_, dec_->GetDecVtxFmt().stride);287} else {288device_->DrawPrimitiveUP(d3d_prim[prim], D3DPrimCount(d3d_prim[prim], vertexCount), decoded_, dec_->GetDecVtxFmt().stride);289}290} else {291device_->SetStreamSource(0, vb_, 0, dec_->GetDecVtxFmt().stride);292293if (useElements) {294device_->SetIndices(ib_);295296device_->DrawIndexedPrimitive(d3d_prim[prim], 0, 0, numDecodedVerts_, 0, D3DPrimCount(d3d_prim[prim], vertexCount));297} else {298device_->DrawPrimitive(d3d_prim[prim], 0, D3DPrimCount(d3d_prim[prim], vertexCount));299}300}301}302} else {303if (!decOptions_.applySkinInDecode) {304decOptions_.applySkinInDecode = true;305lastVType_ |= (1 << 26);306dec_ = GetVertexDecoder(lastVType_);307}308DecodeVerts(decoded_);309int vertexCount = DecodeInds();310311bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;312if (gstate.isModeThrough()) {313gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);314} else {315gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);316}317318gpuStats.numUncachedVertsDrawn += vertexCount;319prim = IndexGenerator::GeneralPrim((GEPrimitiveType)drawInds_[0].prim);320VERBOSE_LOG(Log::G3D, "Flush prim %i SW! %i verts in one go", prim, vertexCount);321322u16 *inds = decIndex_;323SoftwareTransformResult result{};324SoftwareTransformParams params{};325params.decoded = decoded_;326params.transformed = transformed_;327params.transformedExpanded = transformedExpanded_;328params.fbman = framebufferManager_;329params.texCache = textureCache_;330params.allowClear = true;331params.allowSeparateAlphaClear = false;332params.flippedY = false;333params.usesHalfZ = true;334335if (gstate.getShadeMode() == GE_SHADE_FLAT) {336// We need to rotate the index buffer to simulate a different provoking vertex.337// We do this before line expansion etc.338int indexCount = RemainingIndices(inds);339IndexBufferProvokingLastToFirst(prim, inds, vertexCount);340}341342// We need correct viewport values in gstate_c already.343if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {344ViewportAndScissor vpAndScissor;345ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),346framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),347framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),348vpAndScissor);349UpdateCachedViewportState(vpAndScissor);350}351352int maxIndex = numDecodedVerts_;353SoftwareTransform swTransform(params);354355// Half pixel offset hack.356float xOffset = -1.0f / gstate_c.curRTRenderWidth;357float yOffset = 1.0f / gstate_c.curRTRenderHeight;358359const Lin::Vec3 trans(gstate_c.vpXOffset + xOffset, -gstate_c.vpYOffset + yOffset, gstate_c.vpZOffset * 0.5f + 0.5f);360const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);361swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight > 0, trans, scale);362363swTransform.Transform(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), numDecodedVerts_, &result);364// Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values.365// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.366if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)367result.action = SW_NOT_READY;368369if (textureNeedsApply) {370gstate_c.pixelMapped = result.pixelMapped;371textureCache_->ApplyTexture();372gstate_c.pixelMapped = false;373}374375ApplyDrawState(prim);376377if (result.action == SW_NOT_READY)378swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result);379if (result.setSafeSize)380framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight);381382ApplyDrawStateLate();383384VSShader *vshader = shaderManager_->ApplyShader(false, false, dec_, decOptions_.expandAllWeightsToFloat, true, pipelineState_);385386if (result.action == SW_DRAW_INDEXED) {387if (result.setStencil) {388dxstate.stencilFunc.set(D3DCMP_ALWAYS);389dxstate.stencilRef.set(result.stencilValue);390dxstate.stencilCompareMask.set(255);391}392393// TODO: Add a post-transform cache here for multi-RECTANGLES only.394// Might help for text drawing.395396device_->SetVertexDeclaration(transformedVertexDecl_.Get());397device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, numDecodedVerts_, D3DPrimCount(d3d_prim[prim], result.drawNumTrans), inds, D3DFMT_INDEX16, result.drawBuffer, sizeof(TransformedVertex));398} else if (result.action == SW_CLEAR) {399u32 clearColor = result.color;400float clearDepth = result.depth;401402int mask = gstate.isClearModeColorMask() ? D3DCLEAR_TARGET : 0;403if (gstate.isClearModeAlphaMask()) mask |= D3DCLEAR_STENCIL;404if (gstate.isClearModeDepthMask()) mask |= D3DCLEAR_ZBUFFER;405406if (mask & D3DCLEAR_TARGET) {407framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);408}409410device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24);411412if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) {413int scissorX1 = gstate.getScissorX1();414int scissorY1 = gstate.getScissorY1();415int scissorX2 = gstate.getScissorX2() + 1;416int scissorY2 = gstate.getScissorY2() + 1;417framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor);418}419}420decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;421}422423ResetAfterDrawInline();424framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);425GPUDebug::NotifyDraw();426}427428void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) {429// TODO430}431432433