ghaerr / microwindows

The Nano-X Window System
Other
670 stars 92 forks source link

puzzling issue with bitblt #24

Closed roozbehid closed 5 years ago

roozbehid commented 5 years ago

I have a strange issue which I can not figure out.

This is the code I have

HDC hDCMem = CreateCompatibleDC(hdc);
HBITMAP bitmap = CreateDIBSection(hDCMem, &bi, DIB_RGB_COLORS, (VOID**)&lpBitmapBits, NULL, 0);
HGDIOBJ oldbmp = SelectObject(hDCMem, bitmap);

BitBlt(hDCMem, 0, 0, width, height, hdc, 0, 0, SRCCOPY);

`

this is hdc image

and this is result of hDCMem

image

Obviously some cliping happening somewhere. and hdc came from BeginPaint and WMPaint event.

Can you point me to how this happens? What variables should I look at?

Anyway it seems mostly ok, what is not ok, I guess is, the 0,0 of the resultant bitblt. I think what I want is that window get drawn from 0,0. But funny thing is if I change

BitBlt(hDCMem, 0, 0, width, height, hdc, 0, 0, SRCCOPY);

to for example

BitBlt(hDCMem, 0, 0, width, height, hdc, 80, 80, SRCCOPY);

you get this

image

You would think that picture would shift to 0,0 but no! I am kind of going crazy over this :D

ghaerr commented 5 years ago

I'm not really following what your problem is, nor what you're looking to output. A couple questions:

1) Is this something that works on Windows and does not on Microwindows?

2) The dc from BeginPaint has the "update region" anded with it, which means that if you haven't called InvalidateRect(NULL) then you won't get any output. To get around this, read the comment in mwin/wingdi.c::GetDC(). You can call dc = GetDC() instead or use the DCX_EXCLUDEUPDATE flag with GetDCEx().

In the last bit, you're just changing the address in the source image from 0,0 to 80,80, that means that 80,80 in the source will be displayed at 0,0.

What is the source image you're trying to draw? Is it just an image that you're trying to draw into the client area of the window? I'm sorry I'm not quite following the problem.

roozbehid commented 5 years ago

In the last bit, you're just changing the address in the source image from 0,0 to 80,80, that means that 80,80 in the source will be displayed at 0,0.

Yes but it's not.

What is the source image you're trying to draw? Is it just an image that you're trying to draw into the client area of the window? I'm sorry I'm not quite following the problem.

Did you see the images? Source image is the hdc, exactly as I sent in the first image. And result of Bitblt is the second image with 0,0 and third image with 80,80.

So I assume if I changed 0,0 to 80,80, that Box would move the left, but it didnt.

I think that "update region" you mentioned explains something....I'll look into that.

What I am showing in the images, are "watch list" of visual studio, with some cool plugin, that visualizes the mwscreendevice variable. so in the following image

image

what you see on the left (1) is names of variables, and what you see on right (2) is the visualization of that variable,all while debugging. So on those images I sent to you just focus on the right part.

ghaerr commented 5 years ago

Does this work on regular Windows and not Microwindows?

I’m still not following on what you mean by “box not moved to the left”. The first image is the microwindows desktop screen and a frame window with tabs drawn. The other images look like non-drawn portions of a frame window with the client area excluded. Sorry I’m not following what you are drawing and also don’t know what the bitmap is you’re drawing.

There could certainly be a bug in the BitBlt code regarding source offsets. But I need to know whether it works on windows to understand whether this is a coding issue or a compatibility issue.

On Feb 27, 2019, at 10:23 PM, roozbehid notifications@github.com wrote:

In the last bit, you're just changing the address in the source image from 0,0 to 80,80, that means that 80,80 in the source will be displayed at 0,0.

Yes but it's not.

What is the source image you're trying to draw? Is it just an image that you're trying to draw into the client area of the window? I'm sorry I'm not quite following the problem.

Did you see the images? Source image is the hdc, exactly as I sent in the first image. And result of Bitblt is the second image with 0,0 and third image with 80,80.

So I assume if I changed 0,0 to 80,80, that Box would move the left, but it didnt.

I think that "update region" you mentioned explains something....I'll look into that.

What I am showing in the images, are "watch list" of visual studio, with some cool plugin, that visualizes the mwscreendevice variable. so in the following image

https://user-images.githubusercontent.com/7875383/53542988-2c2fed80-3ade-11e9-8e0a-93b347847f5c.png what you see on the left (1) is names of variables, and what you see on right (2) is the visualization of that variable,all while debugging. So on those images I sent to you just focus on the right part.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ghaerr/microwindows/issues/24#issuecomment-468142150, or mute the thread https://github.com/notifications/unsubscribe-auth/ALbi5TAoNwDFKpqq6e2WswlSx2xQ67LQks5vR2figaJpZM4bWAgc.

roozbehid commented 5 years ago

Does this work on regular Windows and not Microwindows?

I dont know. It is really hard to find that out. There is a huge code base that does so many things. So maybe everything is fine and bug is on my side.

I’m still not following on what you mean by “box not moved to the left”. The first image is the microwindows desktop screen and a frame window with tabs drawn. The other images look like non-drawn portions of a frame window with the client area excluded. Sorry I’m not following what you are drawing and also don’t know what the bitmap is you’re drawing. There could certainly be a bug in the BitBlt code regarding source offsets. But I need to know whether it works on windows to understand whether this is a coding issue or a compatibility issue.

I am asking this question to more educate myself, because something seems a bit strange here to me, or I don't have enough knowledge on it.

So here maybe some other explanation to what I find strange.

This is how I am getting the secondImage, Lets not discuss why I just got a simple frame. Probably because of cliping of regions or some clienttoscreen or etc....I dont care....

BitBlt (SecondImage, 0, 0, w, h, FirstImage, 0, 0, SRCCOPY)

For this : BitBlt (ThirdImage, 0, 0, w, h, FirstImage, 80, 80, SRCCOPY)

You are not expecting to get what you see in third image. I did not posted info pixelwise on 3rd and 2nd image. But the location of start of frame in 2nd and 3rd image is same.

I would expect to get this

image

but I am not. I am getting this

image

I also did following test.

HDC hDCMem2 = CreateCompatibleDC(GetDC(0));
HBITMAP bitmap2 = CreateDIBSection(hDCMem2, &bi, DIB_RGB_COLORS, (VOID**)&lpBitmapBits2, NULL, 0);
HGDIOBJ oldbmp2 = SelectObject(hDCMem2, bitmap2);

To create a new bitmap and copy from second image. I am still seeing those clipping regions in effect.

Then I went and looked into BitBlt -> GdBlit -> GdConvBlitInternal and saw extern MWCLIPREGION *clipregion;

So it seems to me there is a global clipping region in effect, and I have a feeling that it is applied to any destination HDC or bitmap, which sounds wrong to me.

For example even in the middle of BeginPaint or in middle of any operation. I should be able to capture whole screen (like screen capture) and save it into a bitmap. Is it possible? It seems not possible to me.

I hope I could explain it. If not also no worries...

roozbehid commented 5 years ago

So yes. I went and looked into clipregion and it had four rectangles in it, which are making up those rectangle (frame) you see in those images. So it seems they are applied to any HDC. Seems wrong to be. But I think I can save it and then restore it or something as a workaround

ghaerr commented 5 years ago

Try getting a separate dc with GetDC as discussed before, don’t use BeginPaint dc.

On Feb 27, 2019, at 11:37 PM, roozbehid notifications@github.com wrote:

So yes. I went and looked into clipregion and it had four rectangles in it, which are making up those rectangle (frame) you see in those images. So it seems they are applied to any HDC. Seems wrong to be. But I think I can save it and then restore it or something as a workaround

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

roozbehid commented 5 years ago

Thats what I did in the above code. I used GetDC(0), it does work in Windows. It doesnt work in Microwindows.

roozbehid commented 5 years ago

ok this new piece of code fixed all my bad drawing problems.

/* if dst screen DC, convert coords and set clipping*/
/* FIXME: if dest is also screen, src clipping will be overwritten*/

if(!MwIsMemDC(hdcDest) && MwIsClientDC(hdcDest)) {
    if(!(hwnd = MwPrepareDC(hdcDest)))
        return FALSE;
    ClientToScreen(hwnd, &dst);
}
else {
    MwPrepareDC(hdcDest);
}

it is to replace wingdi.c:1914

ghaerr commented 5 years ago

Thanks for debugging and fixing BitBlt when hdc is a memory DC. Sorry you had to delve deep into the clipping code, but this is where the fun is in windowing systems lol.

Microwindows clipping is setup as a global structure for speed and clip caching, but it needs to be initialized every time the hdc changes in a draw operation. For the memory DC case, it was never being done, due to some prior trickery regarding trying to get src DC clipping to work, which is not implemented anyways.

I commit a change very close to your fix, please pull it and let me know everything still works.

roozbehid commented 5 years ago

Thanks. Yes that commit is good too.