From: Dmitry Timoshkov Subject: Re: [PATCH v3] d2d1: Make ID2D1Device::CreateImageBrush() accept only bitmap as a source image. Message-Id: <20220603154047.fb00c30302b3a7dd1be5bdb2@baikal.ru> Date: Fri, 3 Jun 2022 15:40:47 +0300 In-Reply-To: <39ae6dde-d294-9a87-dc40-58e849ef4927@codeweavers.com> References: <20220519143447.31b8554410e1e9237043b7ea@baikal.ru> <20220525185829.f1cc15d5e5ac0815fb70374e@baikal.ru> <6f2fb2f0-213c-c6fb-8c7f-734bf90164e5@codeweavers.com> <20220526143452.ab817f7262509feb75572244@baikal.ru> <408d4b5a-ccd1-f27e-a4aa-1fcc947be5e3@codeweavers.com> <20220526171532.cc6b619beb274f3c7a4d25ea@baikal.ru> <996576ea-9376-0627-0dbf-798b471df322@codeweavers.com> <20220526173645.8a040b30c5bc24dcbb00a26b@baikal.ru> <39ae6dde-d294-9a87-dc40-58e849ef4927@codeweavers.com> Nikolay Sivov wrote: > On 5/26/22 17:36, Dmitry Timoshkov wrote: > > Nikolay Sivov wrote: > > > >> On 5/26/22 17:15, Dmitry Timoshkov wrote: > >>> Nikolay Sivov wrote: > >>> > >>>> On 5/26/22 14:34, Dmitry Timoshkov wrote: > >>>>> Nikolay Sivov wrote: > >>>>> > >>>>>> On 5/25/22 18:58, Dmitry Timoshkov wrote: > >>>>>>> Dmitry Timoshkov wrote: > >>>>>>> > >>>>>>>> ID2D1Bitmap derives from ID2D1Image, which in turn derives from ID2D1Resource. > >>>>>>>> That means that ID2D1Device::CreateImageBrush() can't be really passed anything > >>>>>>>> but a ID2D1Bitmap* represented as a ID2D1Image*. > >>>>>>>> > >>>>>>>> I've added QueryInterface+FIXME just in case, probably it could be dropped. > >>>>>>>> > >>>>>>>> v2: Fix test crashes with image == NULL. > >>>>>>>> v3: Add a QueryInterface() check to SetImage(). > >>>>>>> Is there anything that could be improved in this patch to make it acceptable? > >>>>>>> Probably I should add once again, that this patch allows a bitmap work as an > >>>>>>> image brush (unlike current broken state) and actually makes work the app that > >>>>>>> have here. > >>>>>>> > >>>>>> Same thing I mention last time - it's backwards. Bitmap brush could > >>>>>> probably be implemented as image brush, but not the other way. I don't > >>>>>> think you'll need any shader changes for that. > >>>>> Do you mean something like the attached patch, or do I miss something? > >>>>> With the attached patch (on top of just sent ::Map()/::Unmap() patches) > >>>>> I get areas filled with black in the application that I'm working on, > >>>>> unlike with the proposed patch where I get correctly filled areas with > >>>>> a proper brush. > >>>>> > >>>> I suspect black color is from this in sample_brush(): > >>>> > >>>> return float4(0.0, 0.0, 0.0, brush.opacity); > >>>> > >>>> Which means you didn't set brush type correctly in the constant buffer. > >>> I also think that's the source of the problem. However that's the shader > >>> code, and you mentioned above that I don't need them to make image brush > >>> work. Or did I misunderstand something? Do you have a suggestion for that? > >>> > >> Brush type is set in d2d_brush_fill_cb(), trying setting it "correctly" > >> to bitmap brush type. > > Thank you very much, setting cb->type to TYPE_BITMAP in the TYPE_IMAGE case > > has fixed painting in my application. Do you think that the patch I attached > > in my previous reply with this fix is an acceptable solution, or there are > > other things you'd like to see addressed? > > > I think we should avoid duplication of bind_bitmap() function, since > it's exactly the same. Probably passing image brush description there, > which could be filled from bitmap brush description, expect for source > rectangle. Thanks for the helpful pointers. Does the attached patch match your suggestions? The patch works prety well with the application that I have here. -- Dmitry. From b9333913d37045f2e2a15212f69fe121dd109ced Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Fri, 3 Jun 2022 15:36:19 +0300 Subject: [PATCH] d2d1: Add support for painting image brush as a bitmap. Content-Type: text/plain; charset=UTF-8 To: wine-devel@winehq.org Signed-off-by: Dmitry Timoshkov --- dlls/d2d1/brush.c | 85 ++++++++++++++++++++++++++++++++++++++++------ dlls/d2d1/device.c | 2 +- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/dlls/d2d1/brush.c b/dlls/d2d1/brush.c index b9a673fe54c..7febafc375c 100644 --- a/dlls/d2d1/brush.c +++ b/dlls/d2d1/brush.c @@ -1450,7 +1450,23 @@ BOOL d2d_brush_fill_cb(const struct d2d_brush *brush, struct d2d_brush_cb *cb) return TRUE; case D2D_BRUSH_TYPE_BITMAP: - bitmap = brush->u.bitmap.bitmap; + case D2D_BRUSH_TYPE_IMAGE: + { + ID2D1Bitmap *src_bitmap; + + if (brush->type == D2D_BRUSH_TYPE_BITMAP) + bitmap = brush->u.bitmap.bitmap; + else + { + if (FAILED(ID2D1Image_QueryInterface(brush->u.image.image, &IID_ID2D1Bitmap, (void **)&src_bitmap))) + { + FIXME("ID2D1Image doesn't support ID2D1Bitmap interface.\n"); + return FALSE; + } + + bitmap = unsafe_impl_from_ID2D1Bitmap(src_bitmap); + cb->type = D2D_BRUSH_TYPE_BITMAP; + } /* Scale for bitmap size and dpi. */ b = brush->transform; @@ -1477,7 +1493,11 @@ BOOL d2d_brush_fill_cb(const struct d2d_brush *brush, struct d2d_brush_cb *cb) cb->u.bitmap.ignore_alpha = bitmap->format.alphaMode == D2D1_ALPHA_MODE_IGNORE; + if (brush->type == D2D_BRUSH_TYPE_IMAGE) + ID2D1Bitmap_Release(src_bitmap); + return TRUE; + } default: FIXME("Unhandled brush type %#x.\n", brush->type); @@ -1485,31 +1505,31 @@ BOOL d2d_brush_fill_cb(const struct d2d_brush *brush, struct d2d_brush_cb *cb) } } -static void d2d_brush_bind_bitmap(struct d2d_brush *brush, struct d2d_device_context *context, - unsigned int brush_idx) +static void d2d_brush_bind(struct d2d_bitmap *bitmap, struct d2d_device_context *context, + const D2D1_IMAGE_BRUSH_PROPERTIES *image_brush_desc, unsigned int brush_idx) { ID3D11SamplerState **sampler_state; ID3D11DeviceContext *d3d_context; HRESULT hr; ID3D11Device1_GetImmediateContext(context->d3d_device, &d3d_context); - ID3D11DeviceContext_PSSetShaderResources(d3d_context, brush_idx, 1, &brush->u.bitmap.bitmap->srv); + ID3D11DeviceContext_PSSetShaderResources(d3d_context, brush_idx, 1, &bitmap->srv); sampler_state = &context->sampler_states - [brush->u.bitmap.interpolation_mode % D2D_SAMPLER_INTERPOLATION_MODE_COUNT] - [brush->u.bitmap.extend_mode_x % D2D_SAMPLER_EXTEND_MODE_COUNT] - [brush->u.bitmap.extend_mode_y % D2D_SAMPLER_EXTEND_MODE_COUNT]; + [image_brush_desc->interpolationMode % D2D_SAMPLER_INTERPOLATION_MODE_COUNT] + [image_brush_desc->extendModeX % D2D_SAMPLER_EXTEND_MODE_COUNT] + [image_brush_desc->extendModeY % D2D_SAMPLER_EXTEND_MODE_COUNT]; if (!*sampler_state) { D3D11_SAMPLER_DESC sampler_desc; - if (brush->u.bitmap.interpolation_mode == D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR) + if (image_brush_desc->interpolationMode == D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR) sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; else sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - sampler_desc.AddressU = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_x); - sampler_desc.AddressV = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_y); + sampler_desc.AddressU = texture_address_mode_from_extend_mode(image_brush_desc->extendModeX); + sampler_desc.AddressV = texture_address_mode_from_extend_mode(image_brush_desc->extendModeY); sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; sampler_desc.MipLODBias = 0.0f; sampler_desc.MaxAnisotropy = 0; @@ -1529,6 +1549,47 @@ static void d2d_brush_bind_bitmap(struct d2d_brush *brush, struct d2d_device_con ID3D11DeviceContext_Release(d3d_context); } +static void d2d_brush_bind_bitmap(struct d2d_brush *brush, struct d2d_device_context *context, + unsigned int brush_idx) +{ + D2D1_IMAGE_BRUSH_PROPERTIES image_brush_desc; + + image_brush_desc.sourceRectangle.left = 0.0f; + image_brush_desc.sourceRectangle.top = 0.0f; + image_brush_desc.sourceRectangle.right = brush->u.bitmap.bitmap->pixel_size.width; + image_brush_desc.sourceRectangle.bottom = brush->u.bitmap.bitmap->pixel_size.height; + image_brush_desc.extendModeX = brush->u.bitmap.extend_mode_x; + image_brush_desc.extendModeY = brush->u.bitmap.extend_mode_y; + image_brush_desc.interpolationMode = brush->u.bitmap.interpolation_mode; + + d2d_brush_bind(brush->u.bitmap.bitmap, context, &image_brush_desc, brush_idx); +} + +static void d2d_brush_bind_image(struct d2d_brush *brush, struct d2d_device_context *context, + unsigned int brush_idx) +{ + ID2D1Bitmap *src_bitmap; + struct d2d_bitmap *bitmap; + D2D1_IMAGE_BRUSH_PROPERTIES image_brush_desc; + + if (FAILED(ID2D1Image_QueryInterface(brush->u.image.image, &IID_ID2D1Bitmap, (void **)&src_bitmap))) + { + FIXME("ID2D1Image doesn't support ID2D1Bitmap interface.\n"); + return; + } + + bitmap = unsafe_impl_from_ID2D1Bitmap(src_bitmap); + + image_brush_desc.sourceRectangle = brush->u.image.source_rect; + image_brush_desc.extendModeX = brush->u.bitmap.extend_mode_x; + image_brush_desc.extendModeY = brush->u.bitmap.extend_mode_y; + image_brush_desc.interpolationMode = brush->u.bitmap.interpolation_mode; + + d2d_brush_bind(bitmap, context, &image_brush_desc, brush_idx); + + ID2D1Bitmap_Release(src_bitmap); +} + void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_device_context *context, unsigned int brush_idx) { switch (brush->type) @@ -1548,6 +1609,10 @@ void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_device_context d2d_brush_bind_bitmap(brush, context, brush_idx); break; + case D2D_BRUSH_TYPE_IMAGE: + d2d_brush_bind_image(brush, context, brush_idx); + break; + default: FIXME("Unhandled brush type %#x.\n", brush->type); break; diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 12aa2acc331..a619c006885 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -1043,7 +1043,7 @@ static void STDMETHODCALLTYPE d2d_device_context_FillGeometry(ID2D1DeviceContext if (FAILED(context->error.code)) return; - if (opacity_brush && brush_impl->type != D2D_BRUSH_TYPE_BITMAP) + if (opacity_brush && !(brush_impl->type == D2D_BRUSH_TYPE_BITMAP || brush_impl->type == D2D_BRUSH_TYPE_IMAGE)) { d2d_device_context_set_error(context, D2DERR_INCOMPATIBLE_BRUSH_TYPES); return; -- 2.36.1