Signed-off-by: James McDonnell topgamer7@gmail.com --- dlls/d3d11/d3d11_private.h | 6 ++-- dlls/d3d11/device.c | 40 ++++++++++++++++++++++---- dlls/d3d11/state.c | 58 ++++++++++++++++++++++++++++---------- 3 files changed, 80 insertions(+), 24 deletions(-)
diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h index efe26551258..b8faf457870 100644 --- a/dlls/d3d11/d3d11_private.h +++ b/dlls/d3d11/d3d11_private.h @@ -411,7 +411,7 @@ HRESULT d3d11_class_linkage_create(struct d3d_device *device, /* ID3D11BlendState, ID3D10BlendState1 */ struct d3d_blend_state { - ID3D11BlendState ID3D11BlendState_iface; + ID3D11BlendState1 ID3D11BlendState1_iface; ID3D10BlendState1 ID3D10BlendState1_iface; LONG refcount;
@@ -422,9 +422,9 @@ struct d3d_blend_state ID3D11Device2 *device; };
-static inline struct d3d_blend_state *impl_from_ID3D11BlendState(ID3D11BlendState *iface) +static inline struct d3d_blend_state *impl_from_ID3D11BlendState(ID3D11BlendState1 *iface) { - return CONTAINING_RECORD(iface, struct d3d_blend_state, ID3D11BlendState_iface); + return CONTAINING_RECORD(iface, struct d3d_blend_state, ID3D11BlendState1_iface); }
HRESULT d3d_blend_state_create(struct d3d_device *device, const D3D11_BLEND_DESC *desc, diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index ecf45e9ce33..117620472f5 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -2204,7 +2204,7 @@ static void STDMETHODCALLTYPE d3d11_device_context_OMGetBlendState(ID3D11DeviceC if (wined3d_state) { blend_state_impl = wined3d_blend_state_get_parent(wined3d_state); - ID3D11BlendState_AddRef(*blend_state = &blend_state_impl->ID3D11BlendState_iface); + ID3D11BlendState_AddRef(*blend_state = &blend_state_impl->ID3D11BlendState1_iface); } else *blend_state = NULL; @@ -3644,7 +3644,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateBlendState(ID3D11Device2 *if if (FAILED(hr = d3d_blend_state_create(device, desc, &object))) return hr;
- *blend_state = &object->ID3D11BlendState_iface; + *blend_state = &object->ID3D11BlendState1_iface;
return S_OK; } @@ -4282,11 +4282,39 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateDeferredContext1(ID3D11Devic }
static HRESULT STDMETHODCALLTYPE d3d11_device_CreateBlendState1(ID3D11Device2 *iface, - const D3D11_BLEND_DESC1 *desc, ID3D11BlendState1 **state) + const D3D11_BLEND_DESC1 *desc, ID3D11BlendState1 **blend_state) { - FIXME("iface %p, desc %p, state %p stub!\n", iface, desc, state); + struct d3d_device *device = impl_from_ID3D11Device2(iface); + struct d3d_blend_state *object; + HRESULT hr; + unsigned i, j; + D3D11_BLEND_DESC simple_desc;
- return E_NOTIMPL; + TRACE("iface %p, desc %p, blend_state %p.\n", iface, desc, blend_state); + FIXME("Logical operations are not implemented.\n"); + + memset(&simple_desc, 0, sizeof(simple_desc)); + simple_desc.AlphaToCoverageEnable = desc->AlphaToCoverageEnable; + simple_desc.IndependentBlendEnable = desc->IndependentBlendEnable; + for (i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) + { + j = desc->IndependentBlendEnable ? i : 0; + simple_desc.RenderTarget[i].BlendEnable = desc->RenderTarget[j].BlendEnable; + simple_desc.RenderTarget[i].SrcBlend = desc->RenderTarget[j].SrcBlend; + simple_desc.RenderTarget[i].DestBlend = desc->RenderTarget[j].DestBlend; + simple_desc.RenderTarget[i].BlendOp = desc->RenderTarget[j].BlendOp; + simple_desc.RenderTarget[i].SrcBlendAlpha = desc->RenderTarget[j].SrcBlendAlpha; + simple_desc.RenderTarget[i].DestBlendAlpha = desc->RenderTarget[j].DestBlendAlpha; + simple_desc.RenderTarget[i].BlendOpAlpha = desc->RenderTarget[j].BlendOpAlpha; + simple_desc.RenderTarget[i].RenderTargetWriteMask = desc->RenderTarget[j].RenderTargetWriteMask; + } + + if (FAILED(hr = d3d_blend_state_create(device, &simple_desc, &object))) + return hr; + + *blend_state = (ID3D11BlendState1*)&object->ID3D11BlendState1_iface; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d3d11_device_CreateRasterizerState1(ID3D11Device2 *iface, @@ -4993,7 +5021,7 @@ static void STDMETHODCALLTYPE d3d10_device_OMSetBlendState(ID3D10Device1 *iface,
blend_state_object = unsafe_impl_from_ID3D10BlendState(blend_state); d3d11_device_context_OMSetBlendState(&device->immediate_context.ID3D11DeviceContext1_iface, - blend_state_object ? &blend_state_object->ID3D11BlendState_iface : NULL, blend_factor, sample_mask); + blend_state_object ? &blend_state_object->ID3D11BlendState1_iface : NULL, blend_factor, sample_mask); }
static void STDMETHODCALLTYPE d3d10_device_OMSetDepthStencilState(ID3D10Device1 *iface, diff --git a/dlls/d3d11/state.c b/dlls/d3d11/state.c index f67017ff1ef..6c8d8fa611c 100644 --- a/dlls/d3d11/state.c +++ b/dlls/d3d11/state.c @@ -23,7 +23,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d11);
/* ID3D11BlendState methods */
-static HRESULT STDMETHODCALLTYPE d3d11_blend_state_QueryInterface(ID3D11BlendState *iface, +static HRESULT STDMETHODCALLTYPE d3d11_blend_state_QueryInterface(ID3D11BlendState1 *iface, REFIID riid, void **object) { struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface); @@ -54,7 +54,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_blend_state_QueryInterface(ID3D11BlendSta return E_NOINTERFACE; }
-static ULONG STDMETHODCALLTYPE d3d11_blend_state_AddRef(ID3D11BlendState *iface) +static ULONG STDMETHODCALLTYPE d3d11_blend_state_AddRef(ID3D11BlendState1 *iface) { struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface); ULONG refcount = InterlockedIncrement(&state->refcount); @@ -70,7 +70,7 @@ static ULONG STDMETHODCALLTYPE d3d11_blend_state_AddRef(ID3D11BlendState *iface) return refcount; }
-static ULONG STDMETHODCALLTYPE d3d11_blend_state_Release(ID3D11BlendState *iface) +static ULONG STDMETHODCALLTYPE d3d11_blend_state_Release(ID3D11BlendState1 *iface) { struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface); ULONG refcount = InterlockedDecrement(&state->refcount); @@ -87,7 +87,7 @@ static ULONG STDMETHODCALLTYPE d3d11_blend_state_Release(ID3D11BlendState *iface return refcount; }
-static void STDMETHODCALLTYPE d3d11_blend_state_GetDevice(ID3D11BlendState *iface, +static void STDMETHODCALLTYPE d3d11_blend_state_GetDevice(ID3D11BlendState1 *iface, ID3D11Device **device) { struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface); @@ -98,7 +98,7 @@ static void STDMETHODCALLTYPE d3d11_blend_state_GetDevice(ID3D11BlendState *ifac ID3D11Device_AddRef(*device); }
-static HRESULT STDMETHODCALLTYPE d3d11_blend_state_GetPrivateData(ID3D11BlendState *iface, +static HRESULT STDMETHODCALLTYPE d3d11_blend_state_GetPrivateData(ID3D11BlendState1 *iface, REFGUID guid, UINT *data_size, void *data) { struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface); @@ -108,7 +108,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_blend_state_GetPrivateData(ID3D11BlendSta return d3d_get_private_data(&state->private_store, guid, data_size, data); }
-static HRESULT STDMETHODCALLTYPE d3d11_blend_state_SetPrivateData(ID3D11BlendState *iface, +static HRESULT STDMETHODCALLTYPE d3d11_blend_state_SetPrivateData(ID3D11BlendState1 *iface, REFGUID guid, UINT data_size, const void *data) { struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface); @@ -118,7 +118,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_blend_state_SetPrivateData(ID3D11BlendSta return d3d_set_private_data(&state->private_store, guid, data_size, data); }
-static HRESULT STDMETHODCALLTYPE d3d11_blend_state_SetPrivateDataInterface(ID3D11BlendState *iface, +static HRESULT STDMETHODCALLTYPE d3d11_blend_state_SetPrivateDataInterface(ID3D11BlendState1 *iface, REFGUID guid, const IUnknown *data) { struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface); @@ -128,7 +128,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_blend_state_SetPrivateDataInterface(ID3D1 return d3d_set_private_data_interface(&state->private_store, guid, data); }
-static void STDMETHODCALLTYPE d3d11_blend_state_GetDesc(ID3D11BlendState *iface, D3D11_BLEND_DESC *desc) +static void STDMETHODCALLTYPE d3d11_blend_state_GetDesc(ID3D11BlendState1 *iface, D3D11_BLEND_DESC *desc) { struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface);
@@ -137,7 +137,33 @@ static void STDMETHODCALLTYPE d3d11_blend_state_GetDesc(ID3D11BlendState *iface, *desc = state->desc; }
-static const struct ID3D11BlendStateVtbl d3d11_blend_state_vtbl = +static void STDMETHODCALLTYPE d3d11_blend_state_GetDesc1(ID3D11BlendState1 *iface, D3D11_BLEND_DESC1 *desc) +{ + struct d3d_blend_state *state = impl_from_ID3D11BlendState(iface); + D3D11_BLEND_DESC1 d3d11_1_desc; + unsigned i; + + TRACE("iface %p, desc %p.\n", iface, desc); + FIXME("LogicOp is not yet supported.\n"); + + d3d11_1_desc.AlphaToCoverageEnable = desc->AlphaToCoverageEnable; + d3d11_1_desc.IndependentBlendEnable = desc->IndependentBlendEnable; + for (i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) { + d3d11_1_desc.RenderTarget[i].BlendEnable = desc->RenderTarget[i].BlendEnable; + d3d11_1_desc.RenderTarget[i].SrcBlend = desc->RenderTarget[i].SrcBlend; + d3d11_1_desc.RenderTarget[i].DestBlend = desc->RenderTarget[i].DestBlend; + d3d11_1_desc.RenderTarget[i].BlendOp = desc->RenderTarget[i].BlendOp; + d3d11_1_desc.RenderTarget[i].SrcBlendAlpha = desc->RenderTarget[i].SrcBlendAlpha; + d3d11_1_desc.RenderTarget[i].DestBlendAlpha = desc->RenderTarget[i].DestBlendAlpha; + d3d11_1_desc.RenderTarget[i].BlendOpAlpha = desc->RenderTarget[i].BlendOpAlpha; + d3d11_1_desc.RenderTarget[i].LogicOp = D3D11_LOGIC_OP_CLEAR; + d3d11_1_desc.RenderTarget[i].LogicOpEnable = 0; + d3d11_1_desc.RenderTarget[i].RenderTargetWriteMask = desc->RenderTarget[i].RenderTargetWriteMask; + } + *desc = d3d11_1_desc; +} + +static const struct ID3D11BlendState1Vtbl d3d11_blend_state_vtbl = { /* IUnknown methods */ d3d11_blend_state_QueryInterface, @@ -150,6 +176,8 @@ static const struct ID3D11BlendStateVtbl d3d11_blend_state_vtbl = d3d11_blend_state_SetPrivateDataInterface, /* ID3D11BlendState methods */ d3d11_blend_state_GetDesc, + /* ID3D11BlendState1 methods */ + d3d11_blend_state_GetDesc1, };
/* ID3D10BlendState methods */ @@ -168,7 +196,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_blend_state_QueryInterface(ID3D10BlendSta
TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
- return d3d11_blend_state_QueryInterface(&state->ID3D11BlendState_iface, riid, object); + return d3d11_blend_state_QueryInterface(&state->ID3D11BlendState1_iface, riid, object); }
static ULONG STDMETHODCALLTYPE d3d10_blend_state_AddRef(ID3D10BlendState1 *iface) @@ -177,7 +205,7 @@ static ULONG STDMETHODCALLTYPE d3d10_blend_state_AddRef(ID3D10BlendState1 *iface
TRACE("iface %p.\n", iface);
- return d3d11_blend_state_AddRef(&state->ID3D11BlendState_iface); + return d3d11_blend_state_AddRef(&state->ID3D11BlendState1_iface); }
static ULONG STDMETHODCALLTYPE d3d10_blend_state_Release(ID3D10BlendState1 *iface) @@ -186,7 +214,7 @@ static ULONG STDMETHODCALLTYPE d3d10_blend_state_Release(ID3D10BlendState1 *ifac
TRACE("iface %p.\n", iface);
- return d3d11_blend_state_Release(&state->ID3D11BlendState_iface); + return d3d11_blend_state_Release(&state->ID3D11BlendState1_iface); }
/* ID3D10DeviceChild methods */ @@ -366,7 +394,7 @@ HRESULT d3d_blend_state_create(struct d3d_device *device, const D3D11_BLEND_DESC object = WINE_RB_ENTRY_VALUE(entry, struct d3d_blend_state, entry);
TRACE("Returning existing blend state %p.\n", object); - ID3D11BlendState_AddRef(&object->ID3D11BlendState_iface); + ID3D11BlendState_AddRef(&object->ID3D11BlendState1_iface); *state = object; wined3d_mutex_unlock();
@@ -379,7 +407,7 @@ HRESULT d3d_blend_state_create(struct d3d_device *device, const D3D11_BLEND_DESC return E_OUTOFMEMORY; }
- object->ID3D11BlendState_iface.lpVtbl = &d3d11_blend_state_vtbl; + object->ID3D11BlendState1_iface.lpVtbl = (struct ID3D11BlendState1Vtbl *)&d3d11_blend_state_vtbl; object->ID3D10BlendState1_iface.lpVtbl = &d3d10_blend_state_vtbl; object->refcount = 1; wined3d_private_store_init(&object->private_store); @@ -436,7 +464,7 @@ struct d3d_blend_state *unsafe_impl_from_ID3D11BlendState(ID3D11BlendState *ifac return NULL; assert(iface->lpVtbl == &d3d11_blend_state_vtbl);
- return impl_from_ID3D11BlendState(iface); + return impl_from_ID3D11BlendState((ID3D11BlendState1 *)iface); }
struct d3d_blend_state *unsafe_impl_from_ID3D10BlendState(ID3D10BlendState *iface)
On Thu, 12 May 2022 at 02:04, James McDonnell topgamer7@gmail.com wrote:
static HRESULT STDMETHODCALLTYPE d3d11_device_CreateBlendState1(ID3D11Device2 *iface,
const D3D11_BLEND_DESC1 *desc, ID3D11BlendState1 **state)
const D3D11_BLEND_DESC1 *desc, ID3D11BlendState1 **blend_state)
{
- FIXME("iface %p, desc %p, state %p stub!\n", iface, desc, state);
- struct d3d_device *device = impl_from_ID3D11Device2(iface);
- struct d3d_blend_state *object;
- HRESULT hr;
- unsigned i, j;
- D3D11_BLEND_DESC simple_desc;
- return E_NOTIMPL;
- TRACE("iface %p, desc %p, blend_state %p.\n", iface, desc, blend_state);
- FIXME("Logical operations are not implemented.\n");
- memset(&simple_desc, 0, sizeof(simple_desc));
- simple_desc.AlphaToCoverageEnable = desc->AlphaToCoverageEnable;
- simple_desc.IndependentBlendEnable = desc->IndependentBlendEnable;
- for (i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
- {
j = desc->IndependentBlendEnable ? i : 0;
simple_desc.RenderTarget[i].BlendEnable = desc->RenderTarget[j].BlendEnable;
simple_desc.RenderTarget[i].SrcBlend = desc->RenderTarget[j].SrcBlend;
simple_desc.RenderTarget[i].DestBlend = desc->RenderTarget[j].DestBlend;
simple_desc.RenderTarget[i].BlendOp = desc->RenderTarget[j].BlendOp;
simple_desc.RenderTarget[i].SrcBlendAlpha = desc->RenderTarget[j].SrcBlendAlpha;
simple_desc.RenderTarget[i].DestBlendAlpha = desc->RenderTarget[j].DestBlendAlpha;
simple_desc.RenderTarget[i].BlendOpAlpha = desc->RenderTarget[j].BlendOpAlpha;
simple_desc.RenderTarget[i].RenderTargetWriteMask = desc->RenderTarget[j].RenderTargetWriteMask;
- }
- if (FAILED(hr = d3d_blend_state_create(device, &simple_desc, &object)))
return hr;
- *blend_state = (ID3D11BlendState1*)&object->ID3D11BlendState1_iface;
- return S_OK;
}
I think at the very least, this patch should modify d3d_blend_state_create() to take a D3D11_BLEND_DESC1 structure instead of a D3D11_BLEND_DESC structure, and store it in the d3d_blend_state structure, so that d3d11_blend_state_GetDesc1() can be properly implemented. Ideally there would then also be a follow-up patch to handle the new fields in wined3d for both the OpenGL and Vulkan backends.
On 2022-05-13 08:55, Henri Verbeet wrote:
On Thu, 12 May 2022 at 02:04, James McDonnell topgamer7@gmail.com wrote:
static HRESULT STDMETHODCALLTYPE d3d11_device_CreateBlendState1(ID3D11Device2 *iface,
const D3D11_BLEND_DESC1 *desc, ID3D11BlendState1 **state)
{const D3D11_BLEND_DESC1 *desc, ID3D11BlendState1 **blend_state)
- FIXME("iface %p, desc %p, state %p stub!\n", iface, desc, state);
- struct d3d_device *device = impl_from_ID3D11Device2(iface);
- struct d3d_blend_state *object;
- HRESULT hr;
- unsigned i, j;
- D3D11_BLEND_DESC simple_desc;
- return E_NOTIMPL;
- TRACE("iface %p, desc %p, blend_state %p.\n", iface, desc, blend_state);
- FIXME("Logical operations are not implemented.\n");
- memset(&simple_desc, 0, sizeof(simple_desc));
- simple_desc.AlphaToCoverageEnable = desc->AlphaToCoverageEnable;
- simple_desc.IndependentBlendEnable = desc->IndependentBlendEnable;
- for (i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
- {
j = desc->IndependentBlendEnable ? i : 0;
simple_desc.RenderTarget[i].BlendEnable = desc->RenderTarget[j].BlendEnable;
simple_desc.RenderTarget[i].SrcBlend = desc->RenderTarget[j].SrcBlend;
simple_desc.RenderTarget[i].DestBlend = desc->RenderTarget[j].DestBlend;
simple_desc.RenderTarget[i].BlendOp = desc->RenderTarget[j].BlendOp;
simple_desc.RenderTarget[i].SrcBlendAlpha = desc->RenderTarget[j].SrcBlendAlpha;
simple_desc.RenderTarget[i].DestBlendAlpha = desc->RenderTarget[j].DestBlendAlpha;
simple_desc.RenderTarget[i].BlendOpAlpha = desc->RenderTarget[j].BlendOpAlpha;
simple_desc.RenderTarget[i].RenderTargetWriteMask = desc->RenderTarget[j].RenderTargetWriteMask;
- }
- if (FAILED(hr = d3d_blend_state_create(device, &simple_desc, &object)))
return hr;
- *blend_state = (ID3D11BlendState1*)&object->ID3D11BlendState1_iface;
- return S_OK; }
I think at the very least, this patch should modify d3d_blend_state_create() to take a D3D11_BLEND_DESC1 structure instead of a D3D11_BLEND_DESC structure, and store it in the d3d_blend_state structure, so that d3d11_blend_state_GetDesc1() can be properly implemented. Ideally there would then also be a follow-up patch to handle the new fields in wined3d for both the OpenGL and Vulkan backends.
I figured this would be a good introductory step to at least partially support software such as Affinity Photo which uses the CreateBlendState1 instead of it purely being a stub and non-functional.
I agree with you that it makes sense to store and use the DESC1 version of the blend state. Which is why I included the fixme warning about the LogicOp. However I have spent a limited amount of time trying to understand OpenGL/Vulkan.
I would think that the step to update blend state to DESC1 should be done at the same time as the update for opengl and vulkan. Because without doing that work you can't actually test the differences that DESC1 puts in place anyway.
From what I could tell, the vulkan struct doesn't neatly line up with the d3d struct however:
typedef struct VkPipelineColorBlendAttachmentState { VkBool32 blendEnable; VkBlendFactor srcColorBlendFactor; VkBlendFactor dstColorBlendFactor; VkBlendOp colorBlendOp; VkBlendFactor srcAlphaBlendFactor; VkBlendFactor dstAlphaBlendFactor; VkBlendOp alphaBlendOp; VkColorComponentFlags colorWriteMask; } VkPipelineColorBlendAttachmentState;
typedef struct VkPipelineColorBlendStateCreateInfo { VkStructureType sType; const void *pNext; VkPipelineColorBlendStateCreateFlags flags; VkBool32 logicOpEnable; VkLogicOp logicOp; uint32_t attachmentCount; const VkPipelineColorBlendAttachmentState *pAttachments; float blendConstants[4]; } VkPipelineColorBlendStateCreateInfo;
---
typedef struct D3D11_RENDER_TARGET_BLEND_DESC1 { BOOL BlendEnable; BOOL LogicOpEnable; D3D11_BLEND SrcBlend; D3D11_BLEND DestBlend; D3D11_BLEND_OP BlendOp; D3D11_BLEND SrcBlendAlpha; D3D11_BLEND DestBlendAlpha; D3D11_BLEND_OP BlendOpAlpha; D3D11_LOGIC_OP LogicOp; UINT8 RenderTargetWriteMask; } D3D11_RENDER_TARGET_BLEND_DESC1;
typedef struct D3D11_BLEND_DESC1 { BOOL AlphaToCoverageEnable; BOOL IndependentBlendEnable; D3D11_RENDER_TARGET_BLEND_DESC1 RenderTarget[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; } D3D11_BLEND_DESC1;
On Sat, May 14, 2022 at 2:38 AM James McDonnell topgamer7@gmail.com wrote:
I would think that the step to update blend state to DESC1 should be done at the same time as the update for opengl and vulkan. Because without doing that work you can't actually test the differences that DESC1 puts in place anyway.
There is, however, the fact that ID3D11BlendState1 lets you query the description in the form of a D3D11_BLEND_DESC1.
From what I could tell, the vulkan struct doesn't neatly line up with the d3d struct however:
typedef struct VkPipelineColorBlendAttachmentState { VkBool32 blendEnable; VkBlendFactor srcColorBlendFactor; VkBlendFactor dstColorBlendFactor; VkBlendOp colorBlendOp; VkBlendFactor srcAlphaBlendFactor; VkBlendFactor dstAlphaBlendFactor; VkBlendOp alphaBlendOp; VkColorComponentFlags colorWriteMask; } VkPipelineColorBlendAttachmentState;
typedef struct VkPipelineColorBlendStateCreateInfo { VkStructureType sType; const void *pNext; VkPipelineColorBlendStateCreateFlags flags; VkBool32 logicOpEnable; VkLogicOp logicOp; uint32_t attachmentCount; const VkPipelineColorBlendAttachmentState *pAttachments; float blendConstants[4]; } VkPipelineColorBlendStateCreateInfo;
typedef struct D3D11_RENDER_TARGET_BLEND_DESC1 { BOOL BlendEnable; BOOL LogicOpEnable; D3D11_BLEND SrcBlend; D3D11_BLEND DestBlend; D3D11_BLEND_OP BlendOp; D3D11_BLEND SrcBlendAlpha; D3D11_BLEND DestBlendAlpha; D3D11_BLEND_OP BlendOpAlpha; D3D11_LOGIC_OP LogicOp; UINT8 RenderTargetWriteMask; } D3D11_RENDER_TARGET_BLEND_DESC1;
typedef struct D3D11_BLEND_DESC1 { BOOL AlphaToCoverageEnable; BOOL IndependentBlendEnable; D3D11_RENDER_TARGET_BLEND_DESC1 RenderTarget[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; } D3D11_BLEND_DESC1;
In theory, you are correct. In practice, it doesn't matter. The docs (https://docs.microsoft.com/en-us/windows/win32/api/d3d11_1/ns-d3d11_1-d3d11_...) have this to say:
When you set the LogicOpEnable member of the first element of the RenderTarget array (RenderTarget[0]) to TRUE, you must also set the BlendEnable member of RenderTarget[0] to FALSE, and the IndependentBlendEnable member of this D3D11_BLEND_DESC1 to FALSE. This reflects the limitation in hardware that you can't mix logic operations with blending across multiple render targets, and that when you use a logic operation, you must apply the same logic operation to all render targets.
In other words, the logic op has to be the same for all eight RTs, just like in OpenGL (cf. glLogicOp(3G)) and Vulkan. The D3D11 spec (https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec...) agrees.
Why did MS do this when no hardware actually supports per-RT logic ops? I don't know; maybe they were anticipating such hardware appearing someday.