mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
606 lines
18 KiB
C++
606 lines
18 KiB
C++
#include "pch.h"
|
|
#include "Renderer.h"
|
|
#include "App.h"
|
|
#include "Utils.h"
|
|
#include "StrUtils.h"
|
|
#include <VertexTypes.h>
|
|
#include "EffectCompiler.h"
|
|
#include <rapidjson/document.h>
|
|
#include "FrameSourceBase.h"
|
|
#include "DeviceResources.h"
|
|
#include "FrameRateDrawer.h"
|
|
#include "GPUTimer.h"
|
|
#include "CursorDrawer.h"
|
|
#include "EffectDrawer.h"
|
|
#include "UIDrawer.h"
|
|
|
|
|
|
Renderer::Renderer() {}
|
|
|
|
Renderer::~Renderer() {}
|
|
|
|
bool Renderer::Initialize(const std::string& effectsJson) {
|
|
_gpuTimer.reset(new GPUTimer());
|
|
|
|
if (!GetWindowRect(App::GetInstance().GetHwndSrc(), &_srcWndRect)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeWin32ErrorMsg("GetWindowRect 失败"));
|
|
return false;
|
|
}
|
|
|
|
RECT destRect;
|
|
if (!_ResolveEffectsJson(effectsJson, destRect)) {
|
|
SPDLOG_LOGGER_ERROR(logger, "_ResolveEffectsJson 失败");
|
|
return false;
|
|
}
|
|
|
|
ID3D11Texture2D* backBuffer = App::GetInstance().GetDeviceResources().GetBackBuffer();
|
|
|
|
if (App::GetInstance().IsShowFPS()) {
|
|
_frameRateDrawer.reset(new FrameRateDrawer());
|
|
if (!_frameRateDrawer->Initialize(backBuffer, destRect)) {
|
|
SPDLOG_LOGGER_ERROR(logger, "初始化 FrameRateDrawer 失败");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
_UIDrawer.reset(new UIDrawer());
|
|
if (!_UIDrawer->Initialize(backBuffer)) {
|
|
return false;
|
|
}
|
|
|
|
_cursorDrawer.reset(new CursorDrawer());
|
|
if (!_cursorDrawer->Initialize(backBuffer, destRect)) {
|
|
SPDLOG_LOGGER_ERROR(logger, "初始化 CursorDrawer 失败");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void Renderer::Render() {
|
|
if (!_CheckSrcState()) {
|
|
SPDLOG_LOGGER_INFO(logger, "源窗口状态改变,退出全屏");
|
|
App::GetInstance().Quit();
|
|
return;
|
|
}
|
|
|
|
DeviceResources& dr = App::GetInstance().GetDeviceResources();
|
|
ID3D11DeviceContext3* d3dDC = dr.GetD3DDC();
|
|
|
|
if (!_waitingForNextFrame) {
|
|
dr.BeginFrame();
|
|
_gpuTimer->BeginFrame();
|
|
}
|
|
|
|
auto state = App::GetInstance().GetFrameSource().Update();
|
|
_waitingForNextFrame = state == FrameSourceBase::UpdateState::Waiting
|
|
|| state == FrameSourceBase::UpdateState::Error;
|
|
if (_waitingForNextFrame) {
|
|
return;
|
|
}
|
|
|
|
d3dDC->ClearState();
|
|
// 所有渲染都使用三角形带拓扑
|
|
d3dDC->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
|
|
if (!_cursorDrawer->Update()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "更新光标位置失败");
|
|
}
|
|
|
|
// 更新常量
|
|
if (!EffectDrawer::UpdateExprDynamicVars()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "UpdateExprDynamicVars 失败");
|
|
}
|
|
|
|
if (state == FrameSourceBase::UpdateState::NewFrame) {
|
|
for (auto& effect : _effects) {
|
|
effect->Draw();
|
|
}
|
|
} else {
|
|
// 此帧内容无变化
|
|
// 从第一个有动态常量的 Effect 开始渲染
|
|
// 如果没有则只渲染最后一个 Effect 的最后一个 pass
|
|
|
|
size_t i = 0;
|
|
for (; i < _effects.size(); ++i) {
|
|
if (_effects[i]->HasDynamicConstants()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == _effects.size()) {
|
|
// 只渲染最后一个 Effect 的最后一个 pass
|
|
_effects.back()->Draw(true);
|
|
} else {
|
|
for (; i < _effects.size(); ++i) {
|
|
_effects[i]->Draw();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (App::GetInstance().IsShowFPS()) {
|
|
_frameRateDrawer->Draw();
|
|
}
|
|
|
|
_UIDrawer->Draw();
|
|
_cursorDrawer->Draw();
|
|
|
|
dr.EndFrame();
|
|
}
|
|
|
|
bool Renderer::SetFillVS() {
|
|
auto& dr = App::GetInstance().GetDeviceResources();
|
|
|
|
if (!_fillVS) {
|
|
const char* src = "void m(uint i:SV_VERTEXID,out float4 p:SV_POSITION,out float2 c:TEXCOORD){c=float2(i&1,i>>1)*2;p=float4(c.x*2-1,-c.y*2+1,0,1);}";
|
|
|
|
winrt::com_ptr<ID3DBlob> blob;
|
|
if (!dr.CompileShader(true, src, "m", blob.put(), "FillVS")) {
|
|
SPDLOG_LOGGER_ERROR(logger, "编译 FillVS 失败");
|
|
return false;
|
|
}
|
|
|
|
HRESULT hr = dr.GetD3DDevice()->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, _fillVS.put());
|
|
if (FAILED(hr)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeComErrorMsg("创建 FillVS 失败", hr));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto d3dDC = dr.GetD3DDC();
|
|
d3dDC->IASetInputLayout(nullptr);
|
|
d3dDC->IASetVertexBuffers(0, 0, nullptr, nullptr, nullptr);
|
|
d3dDC->VSSetShader(_fillVS.get(), nullptr, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Renderer::SetCopyPS(ID3D11SamplerState* sampler, ID3D11ShaderResourceView* input) {
|
|
auto& dr = App::GetInstance().GetDeviceResources();
|
|
|
|
if (!_copyPS) {
|
|
const char* src = "Texture2D t:register(t0);SamplerState s:register(s0);float4 m(float4 p:SV_POSITION,float2 c:TEXCOORD):SV_Target{return t.Sample(s,c);}";
|
|
|
|
winrt::com_ptr<ID3DBlob> blob;
|
|
if (!dr.CompileShader(false, src, "m", blob.put(), "CopyPS")) {
|
|
SPDLOG_LOGGER_ERROR(logger, "编译 CopyPS 失败");
|
|
return false;
|
|
}
|
|
|
|
HRESULT hr = dr.GetD3DDevice()->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, _copyPS.put());
|
|
if (FAILED(hr)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeComErrorMsg("创建 CopyPS 失败", hr));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto d3dDC = dr.GetD3DDC();
|
|
d3dDC->PSSetShader(_copyPS.get(), nullptr, 0);
|
|
d3dDC->PSSetConstantBuffers(0, 0, nullptr);
|
|
d3dDC->PSSetShaderResources(0, 1, &input);
|
|
d3dDC->PSSetSamplers(0, 1, &sampler);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::SetSimpleVS(ID3D11Buffer* simpleVB) {
|
|
auto& dr = App::GetInstance().GetDeviceResources();
|
|
|
|
if (!_simpleVS) {
|
|
const char* src = "void m(float4 p:SV_POSITION,float2 c:TEXCOORD,out float4 q:SV_POSITION,out float2 d:TEXCOORD) {q=p;d=c;}";
|
|
|
|
winrt::com_ptr<ID3DBlob> blob;
|
|
if (!dr.CompileShader(true, src, "m", blob.put(), "SimpleVS")) {
|
|
SPDLOG_LOGGER_ERROR(logger, "编译 SimpleVS 失败");
|
|
return false;
|
|
}
|
|
|
|
auto d3dDevice = dr.GetD3DDevice();
|
|
|
|
HRESULT hr = d3dDevice->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, _simpleVS.put());
|
|
if (FAILED(hr)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeComErrorMsg("创建 SimpleVS 失败", hr));
|
|
return false;
|
|
}
|
|
|
|
hr = d3dDevice->CreateInputLayout(
|
|
VertexPositionTexture::InputElements,
|
|
VertexPositionTexture::InputElementCount,
|
|
blob->GetBufferPointer(),
|
|
blob->GetBufferSize(),
|
|
_simpleIL.put()
|
|
);
|
|
if (FAILED(hr)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeComErrorMsg("创建 SimpleVS 输入布局失败", hr));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto d3dDC = dr.GetD3DDC();
|
|
d3dDC->IASetInputLayout(_simpleIL.get());
|
|
|
|
UINT stride = sizeof(VertexPositionTexture);
|
|
UINT offset = 0;
|
|
d3dDC->IASetVertexBuffers(0, 1, &simpleVB, &stride, &offset);
|
|
|
|
d3dDC->VSSetShader(_simpleVS.get(), nullptr, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CheckForeground(HWND hwndForeground) {
|
|
wchar_t className[256]{};
|
|
if (!GetClassName(hwndForeground, (LPWSTR)className, 256)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeWin32ErrorMsg("GetClassName 失败"));
|
|
return false;
|
|
}
|
|
|
|
// 排除桌面窗口和 Alt+Tab 窗口
|
|
if (!std::wcscmp(className, L"WorkerW") || !std::wcscmp(className, L"ForegroundStaging") ||
|
|
!std::wcscmp(className, L"MultitaskingViewFrame") || !std::wcscmp(className, L"XamlExplorerHostIslandWindow")
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
RECT rectForground{};
|
|
|
|
// 如果捕获模式可以捕获到弹窗,则允许小的弹窗
|
|
if (App::GetInstance().GetFrameSource().IsScreenCapture()
|
|
&& GetWindowStyle(hwndForeground) & (WS_POPUP | WS_CHILD)
|
|
) {
|
|
if (!Utils::GetWindowFrameRect(hwndForeground, rectForground)) {
|
|
SPDLOG_LOGGER_ERROR(logger, "GetWindowFrameRect 失败");
|
|
return false;
|
|
}
|
|
|
|
// 弹窗如果完全在源窗口客户区内则不退出全屏
|
|
const RECT& srcFrameRect = App::GetInstance().GetFrameSource().GetSrcFrameRect();
|
|
if (rectForground.left >= srcFrameRect.left
|
|
&& rectForground.right <= srcFrameRect.right
|
|
&& rectForground.top >= srcFrameRect.top
|
|
&& rectForground.bottom <= srcFrameRect.bottom
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// 非多屏幕模式下退出全屏
|
|
if (!App::GetInstance().IsMultiMonitorMode()) {
|
|
return false;
|
|
}
|
|
|
|
if (rectForground == RECT{}) {
|
|
if (!Utils::GetWindowFrameRect(hwndForeground, rectForground)) {
|
|
SPDLOG_LOGGER_ERROR(logger, "GetWindowFrameRect 失败");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
IntersectRect(&rectForground, &App::GetInstance().GetHostWndRect(), &rectForground);
|
|
|
|
// 允许稍微重叠,否则前台窗口最大化时会意外退出
|
|
if (rectForground.right - rectForground.left < 10 || rectForground.right - rectForground.top < 10) {
|
|
return true;
|
|
}
|
|
|
|
// 排除开始菜单,它的类名是 CoreWindow
|
|
if (std::wcscmp(className, L"Windows.UI.Core.CoreWindow")) {
|
|
// 记录新的前台窗口
|
|
SPDLOG_LOGGER_INFO(logger, fmt::format("新的前台窗口:\n\t类名:{}", StrUtils::UTF16ToUTF8(className)));
|
|
return false;
|
|
}
|
|
|
|
DWORD dwProcId = 0;
|
|
if (!GetWindowThreadProcessId(hwndForeground, &dwProcId)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeWin32ErrorMsg("GetWindowThreadProcessId 失败"));
|
|
return false;
|
|
}
|
|
|
|
Utils::ScopedHandle hProc(Utils::SafeHandle(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcId)));
|
|
if (!hProc) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeWin32ErrorMsg("OpenProcess 失败"));
|
|
return false;
|
|
}
|
|
|
|
wchar_t fileName[MAX_PATH] = { 0 };
|
|
if (!GetModuleFileNameEx(hProc.get(), NULL, fileName, MAX_PATH)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeWin32ErrorMsg("GetModuleFileName 失败"));
|
|
return false;
|
|
}
|
|
|
|
std::string exeName = StrUtils::UTF16ToUTF8(fileName);
|
|
exeName = exeName.substr(exeName.find_last_of(L'\\') + 1);
|
|
StrUtils::ToLowerCase(exeName);
|
|
|
|
// win10: searchapp.exe 和 startmenuexperiencehost.exe
|
|
// win11: searchhost.exe 和 startmenuexperiencehost.exe
|
|
if (exeName == "searchapp.exe" || exeName == "searchhost.exe" || exeName == "startmenuexperiencehost.exe") {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Renderer::_CheckSrcState() {
|
|
HWND hwndSrc = App::GetInstance().GetHwndSrc();
|
|
|
|
if (!App::GetInstance().IsBreakpointMode()) {
|
|
HWND hwndForeground = GetForegroundWindow();
|
|
if (hwndForeground && hwndForeground != hwndSrc && !CheckForeground(hwndForeground)) {
|
|
SPDLOG_LOGGER_INFO(logger, "前台窗口已改变");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (Utils::GetWindowShowCmd(hwndSrc) != SW_NORMAL) {
|
|
SPDLOG_LOGGER_INFO(logger, "源窗口显示状态改变");
|
|
return false;
|
|
}
|
|
|
|
RECT rect;
|
|
if (!GetWindowRect(hwndSrc, &rect)) {
|
|
SPDLOG_LOGGER_ERROR(logger, "GetWindowRect 失败");
|
|
return false;
|
|
}
|
|
|
|
if (_srcWndRect != rect) {
|
|
SPDLOG_LOGGER_INFO(logger, "源窗口位置或大小改变");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::_ResolveEffectsJson(const std::string& effectsJson, RECT& destRect) {
|
|
_effectInput = App::GetInstance().GetFrameSource().GetOutput();
|
|
D3D11_TEXTURE2D_DESC inputDesc;
|
|
_effectInput->GetDesc(&inputDesc);
|
|
|
|
const RECT& hostWndRect = App::GetInstance().GetHostWndRect();
|
|
SIZE hostSize = { hostWndRect.right - hostWndRect.left,hostWndRect.bottom - hostWndRect.top };
|
|
|
|
rapidjson::Document doc;
|
|
if (doc.Parse(effectsJson.c_str(), effectsJson.size()).HasParseError()) {
|
|
// 解析 json 失败
|
|
SPDLOG_LOGGER_ERROR(logger, fmt::format("解析 json 失败\n\t错误码:{}", doc.GetParseError()));
|
|
return false;
|
|
}
|
|
|
|
if (!doc.IsArray()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:根元素不为数组");
|
|
return false;
|
|
}
|
|
|
|
std::vector<SIZE> texSizes;
|
|
texSizes.push_back({ (LONG)inputDesc.Width, (LONG)inputDesc.Height });
|
|
|
|
const auto& effectsArr = doc.GetArray();
|
|
_effects.reserve(effectsArr.Size());
|
|
texSizes.reserve(static_cast<size_t>(effectsArr.Size()) + 1);
|
|
|
|
// 不得为空
|
|
if (effectsArr.Empty()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:根元素为空");
|
|
return false;
|
|
}
|
|
|
|
for (const auto& effectJson : effectsArr) {
|
|
if (!effectJson.IsObject()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:根数组中存在非法成员");
|
|
return false;
|
|
}
|
|
|
|
EffectDrawer& effect = *_effects.emplace_back(new EffectDrawer());
|
|
|
|
auto effectName = effectJson.FindMember("effect");
|
|
if (effectName == effectJson.MemberEnd() || !effectName->value.IsString()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:未找到 effect 属性或该属性的值不合法");
|
|
return false;
|
|
}
|
|
|
|
if (!effect.Initialize((L"effects\\" + StrUtils::UTF8ToUTF16(effectName->value.GetString()) + L".hlsl").c_str())) {
|
|
SPDLOG_LOGGER_ERROR(logger, fmt::format("初始化效果 {} 失败", effectName->value.GetString()));
|
|
return false;
|
|
}
|
|
|
|
if (effect.CanSetOutputSize()) {
|
|
// scale 属性可用
|
|
auto scaleProp = effectJson.FindMember("scale");
|
|
if (scaleProp != effectJson.MemberEnd()) {
|
|
if (!scaleProp->value.IsArray()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:非法的 scale 属性");
|
|
return false;
|
|
}
|
|
|
|
// scale 属性的值为两个元素组成的数组
|
|
// [+, +]:缩放比例
|
|
// [0, 0]:非等比例缩放到屏幕大小
|
|
// [-, -]:相对于屏幕能容纳的最大等比缩放的比例
|
|
|
|
const auto& scale = scaleProp->value.GetArray();
|
|
if (scale.Size() != 2 || !scale[0].IsNumber() || !scale[1].IsNumber()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:非法的 scale 属性");
|
|
return false;
|
|
}
|
|
|
|
float scaleX = scale[0].GetFloat();
|
|
float scaleY = scale[1].GetFloat();
|
|
|
|
static float DELTA = 1e-5f;
|
|
|
|
SIZE outputSize = texSizes.back();;
|
|
|
|
if (scaleX >= DELTA) {
|
|
if (scaleY < DELTA) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:非法的 scale 属性");
|
|
return false;
|
|
}
|
|
|
|
outputSize = { std::lroundf(outputSize.cx * scaleX), std::lroundf(outputSize.cy * scaleY) };
|
|
} else if (std::abs(scaleX) < DELTA) {
|
|
if (std::abs(scaleY) >= DELTA) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:非法的 scale 属性");
|
|
return false;
|
|
}
|
|
|
|
outputSize = hostSize;
|
|
} else {
|
|
if (scaleY > -DELTA) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:非法的 scale 属性");
|
|
return false;
|
|
}
|
|
|
|
float fillScale = std::min(float(hostSize.cx) / outputSize.cx, float(hostSize.cy) / outputSize.cy);
|
|
outputSize = {
|
|
std::lroundf(outputSize.cx * fillScale * -scaleX),
|
|
std::lroundf(outputSize.cy * fillScale * -scaleY)
|
|
};
|
|
}
|
|
|
|
effect.SetOutputSize(outputSize);
|
|
}
|
|
}
|
|
|
|
#pragma push_macro("GetObject")
|
|
#undef GetObject
|
|
for (const auto& prop : effectJson.GetObject()) {
|
|
#pragma pop_macro("GetObject")
|
|
if (!prop.name.IsString()) {
|
|
SPDLOG_LOGGER_ERROR(logger, "解析 json 失败:非法的效果名");
|
|
return false;
|
|
}
|
|
|
|
std::string_view name = prop.name.GetString();
|
|
|
|
if (name == "effect" || (effect.CanSetOutputSize() && name == "scale")) {
|
|
continue;
|
|
} else {
|
|
auto type = effect.GetConstantType(name);
|
|
if (type == EffectDrawer::ConstantType::Float) {
|
|
if (!prop.value.IsNumber()) {
|
|
SPDLOG_LOGGER_ERROR(logger, fmt::format("解析 json 失败:成员 {} 的类型非法", name));
|
|
return false;
|
|
}
|
|
|
|
if (!effect.SetConstant(name, prop.value.GetFloat())) {
|
|
SPDLOG_LOGGER_ERROR(logger, fmt::format("解析 json 失败:成员 {} 的值非法", name));
|
|
return false;
|
|
}
|
|
} else if (type == EffectDrawer::ConstantType::Int) {
|
|
int value;
|
|
if (prop.value.IsInt()) {
|
|
value = prop.value.GetInt();
|
|
} else if (prop.value.IsBool()) {
|
|
// bool 值视为 int
|
|
value = (int)prop.value.GetBool();
|
|
} else {
|
|
SPDLOG_LOGGER_ERROR(logger, fmt::format("解析 json 失败:成员 {} 的类型非法", name));
|
|
return false;
|
|
}
|
|
|
|
if (!effect.SetConstant(name, value)) {
|
|
SPDLOG_LOGGER_ERROR(logger, fmt::format("解析 json 失败:成员 {} 的值非法", name));
|
|
return false;
|
|
}
|
|
} else {
|
|
SPDLOG_LOGGER_ERROR(logger, fmt::format("解析 json 失败:非法成员 {}", name));
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
SIZE& outputSize = texSizes.emplace_back();
|
|
if (!effect.CalcOutputSize(texSizes[texSizes.size() - 2], outputSize)) {
|
|
SPDLOG_LOGGER_ERROR(logger, "CalcOutputSize 失败");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto& dr = App::GetInstance().GetDeviceResources();
|
|
auto d3dDevice = dr.GetD3DDevice();
|
|
|
|
if (_effects.size() == 1) {
|
|
if (!_effects.back()->Build(_effectInput.get(), dr.GetBackBuffer())) {
|
|
SPDLOG_LOGGER_ERROR(logger, "构建效果失败");
|
|
return false;
|
|
}
|
|
} else {
|
|
// 创建效果间的中间纹理
|
|
winrt::com_ptr<ID3D11Texture2D> curTex = _effectInput;
|
|
|
|
D3D11_TEXTURE2D_DESC desc{};
|
|
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
|
desc.MipLevels = 1;
|
|
desc.ArraySize = 1;
|
|
desc.SampleDesc.Count = 1;
|
|
desc.SampleDesc.Quality = 0;
|
|
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
|
|
|
assert(texSizes.size() == _effects.size() + 1);
|
|
for (size_t i = 0, end = _effects.size() - 1; i < end; ++i) {
|
|
SIZE texSize = texSizes[i + 1];
|
|
desc.Width = texSize.cx;
|
|
desc.Height = texSize.cy;
|
|
|
|
winrt::com_ptr<ID3D11Texture2D> outputTex;
|
|
HRESULT hr = d3dDevice->CreateTexture2D(&desc, nullptr, outputTex.put());
|
|
if (FAILED(hr)) {
|
|
SPDLOG_LOGGER_ERROR(logger, MakeComErrorMsg("CreateTexture2D 失败", hr));
|
|
return false;
|
|
}
|
|
|
|
if (!_effects[i]->Build(curTex.get(), outputTex.get())) {
|
|
SPDLOG_LOGGER_ERROR(logger, "构建效果失败");
|
|
return false;
|
|
}
|
|
|
|
curTex = outputTex;
|
|
}
|
|
|
|
// 最后一个效果输出到后缓冲纹理
|
|
if (!_effects.back()->Build(curTex.get(), dr.GetBackBuffer())) {
|
|
SPDLOG_LOGGER_ERROR(logger, "构建效果失败");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SIZE outputSize = texSizes.back();
|
|
destRect.left = (hostSize.cx - outputSize.cx) / 2;
|
|
destRect.right = destRect.left + outputSize.cx;
|
|
destRect.top = (hostSize.cy - outputSize.cy) / 2;
|
|
destRect.bottom = destRect.top + outputSize.cy;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::SetAlphaBlend(bool enable) {
|
|
auto& dr = App::GetInstance().GetDeviceResources();
|
|
|
|
if (!enable) {
|
|
dr.GetD3DDC()->OMSetBlendState(nullptr, nullptr, 0xffffffff);
|
|
return true;
|
|
}
|
|
|
|
if (!_alphaBlendState) {
|
|
D3D11_BLEND_DESC desc{};
|
|
desc.RenderTarget[0].BlendEnable = TRUE;
|
|
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
|
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
|
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
|
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
|
desc.RenderTarget[0].BlendOp = desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
|
|
|
HRESULT hr = dr.GetD3DDevice()->CreateBlendState(&desc, _alphaBlendState.put());
|
|
if (FAILED(hr)) {
|
|
SPDLOG_LOGGER_CRITICAL(logger, MakeComErrorMsg("CreateBlendState 失败", hr));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
dr.GetD3DDC()->OMSetBlendState(_alphaBlendState.get(), nullptr, 0xffffffff);
|
|
return true;
|
|
}
|