Bug 15792

Summary: nv04 (TNT2) video blitter problem.
Product: xorg Reporter: Andrew Randrianasulu <randrik>
Component: Driver/nouveauAssignee: Nouveau Project <nouveau>
Status: RESOLVED FIXED QA Contact: Xorg Project Team <xorg-team>
Severity: normal    
Priority: medium    
Version: git   
Hardware: x86 (IA32)   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:
Attachments:
Description Flags
xorg log
none
current xorg.conf
none
x.org log - old version
none
noisy log
none
patch which avoids passing sysmem addresses to the gpu when dest pixmap cannot be migrated into offscreen memory none

Description Andrew Randrianasulu 2008-05-01 15:35:09 UTC
Created attachment 16304 [details]
xorg log

Hw:

01:00.0 VGA compatible controller: nVidia Corporation NV5 [RIVA TNT2/TNT2 Pro] (rev 15) (prog-if 00 [VGA])
        Subsystem: ASUSTeK Computer Inc. AGP-V3800PRO
        Flags: bus master, 66MHz, medium devsel, latency 64, IRQ 19
        Memory at de000000 (32-bit, non-prefetchable) [size=16M]
        Memory at da000000 (32-bit, prefetchable) [size=32M]
        Expansion ROM at dfef0000 [disabled] [size=64K]
        Capabilities: [60] Power Management version 1
        Capabilities: [44] AGP version 2.0

[1043:4000]

software:
kernel 2.6.24.5
glibc-2.7
gcc-4.2.2
X server - git 3b8d53452cd6c74d32d7759964a7cd9ee775f161
xf86-video-nouveau - 85536023ed7050632d121299ab99382e096b9984
drm - 3ac74f3208ed15a990a0a26742fbfe566f08aa80


Screen resolution 1024x768, 24bpp. Option "Randr12" "1". (important). Composite extension enabled in xorg.conf, composite manager disabled.

Trying to watch movie in fullscreen resulted in blue rectangle and following errors in dmesg [playing 3 frames in mplayer]: 



[drm] Initialized drm 1.1.0 20060810
ACPI: PCI Interrupt 0000:01:00.0[A] -> GSI 16 (level, low) -> IRQ 19
[drm] Detected an NV4 generation card (0x20154000)
[drm] Initialized nouveau 0.0.10 drm-2.3.0-1227-g3ac74f3208ed15a99 on minor 0
agpgart: Found an AGP 2.0 compliant device at 0000:00:00.0.
agpgart: Putting AGP V2 device at 0000:00:00.0 into 4x mode
agpgart: Putting AGP V2 device at 0000:01:00.0 into 4x mode
[drm] Allocating FIFO number 0
[drm] nouveau_fifo_alloc: initialised FIFO 0
[drm] Allocating FIFO number 1
[drm] nouveau_fifo_alloc: initialised FIFO 1
[drm] NV: PGRAPH context switch interrupt channel 0 -> 1
eth0: no IPv6 routers present
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x0304 Data 0xc03f4380:0x15a815a8
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x0308 Data 0xc03f4380:0xfe2bb038
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x030c Data 0xc03f4380:0xfe2bb038
[drm] PGRAPH_NOTIFY - nSource: STATE_INVALID, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/2 Class 0x0077 Mthd 0x040c Data 0xc03f4380:0x00000000
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x0304 Data 0xd09467d1:0x15a815a8
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x0308 Data 0xd09467d1:0xfe2bb038
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x030c Data 0xd09467d1:0xfe2bb038
[drm] PGRAPH_NOTIFY - nSource: STATE_INVALID, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/2 Class 0x0077 Mthd 0x040c Data 0xd09467d1:0x00000000
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x0304 Data 0xd09467d1:0x15a815a8
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x0308 Data 0xd09467d1:0xfe2bb038
[drm] PGRAPH_NOTIFY - nSource: DATA_ERROR, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/6 Class 0x0042 Mthd 0x030c Data 0xd09467d1:0xfe2bb038
[drm] PGRAPH_NOTIFY - nSource: STATE_INVALID, nStatus: INVALID_STATE BAD_ARGUMENT
[drm] PGRAPH_NOTIFY - Ch 1/2 Class 0x0077 Mthd 0x040c Data 0xd09467d1:0x00000000



Workarounds:
1) Using xrandr and lowering resolution to 832 x 624 at runtime, for example.
2) add "Virtual 1024x768" line in xorg.conf
3) Disable randr12 (X will start with 1024x768 framebuffer)
Comment 1 Andrew Randrianasulu 2008-05-01 15:36:05 UTC
Created attachment 16305 [details]
current xorg.conf
Comment 2 Stephane Marchesin 2008-05-02 02:54:49 UTC
Hmm, is that related to the recent Xv commits ? Could you try a version before those ?
Comment 3 Andrew Randrianasulu 2008-05-02 04:08:26 UTC
(In reply to comment #2)
> Hmm, is that related to the recent Xv commits ? Could you try a version before
> those ?
> 

(II) NOUVEAU driver Date:   Sat Mar 15 01:36:13 2008 +0000

still affected.
Comment 4 Andrew Randrianasulu 2008-05-02 04:11:05 UTC
Created attachment 16308 [details]
x.org log - old version
Comment 5 Stuart Bennett 2008-05-02 12:42:01 UTC
5e1b5708d3a7e4298f80b1a1b8bb3fafae0c69bd may or may not fix this :), please try again.
Comment 6 Andrew Randrianasulu 2008-05-02 13:19:08 UTC
some testing:

randr-1.2                                                                       
EXA_get_pixmap_pitch: 5544                                                      
EXA_get_pixmap_pitch: 5544                                                      
EXA_get_pixmap_pitch: 5544                                                      
 
without randr-1.2                                                               
EXA_get_pixmap_pitch: 5568                                                      
EXA_get_pixmap_pitch: 5568                                                      
EXA_get_pixmap_pitch: 5568                                                      
 
Virtual - 1024x768, randr12 enabled                                             
EXA_get_pixmap_pitch: 5568                                                      
EXA_get_pixmap_pitch: 5568                                                      
EXA_get_pixmap_pitch: 5568
 
diff --git a/src/nv04_video_blitter.c b/src/nv04_video_blitter.c
index 8ee848f..30f4e82 100644
--- a/src/nv04_video_blitter.c
+++ b/src/nv04_video_blitter.c
@@ -94,6 +94,8 @@ NVPutBlitImage(ScrnInfoPtr pScrn, int src_offset, int id,
         BEGIN_RING(NvContextSurfaces, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
         OUT_RING  (dst_format);
         OUT_RING  ((exaGetPixmapPitch(pPix) << 16) | exaGetPixmapPitch(pPix));
+       ErrorF("EXA_get_pixmap_pitch: %d\n", exaGetPixmapPitch(pPix));
+       
         OUT_PIXMAPl(pPix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
         OUT_PIXMAPl(pPix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
Comment 7 Andrew Randrianasulu 2008-05-02 13:29:45 UTC
(In reply to comment #5)
> 5e1b5708d3a7e4298f80b1a1b8bb3fafae0c69bd may or may not fix this :), please try
> again.
> 

no, it doesn't help here
Comment 8 Andrew Randrianasulu 2008-05-03 12:14:13 UTC
ops, this is possible what Destination pixmap (even if it just fullscreen  video window) MUST be in video memory, allocated at startup? Because i found workaround #4: increase vram size, available for EXA  in nv_driver.c:


--------
#if !NOUVEAU_EXA_PIXMAPS                                                        
        if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN,          
                0, (pNv->VRAMPhysicalSize / 4) * 3, &pNv->FB)) {  
--------

now it reported:
 
(--) NOUVEAU(0): Virtual size is 1152x1152 (pitch 1152)
....
(II) NOUVEAU(0): Allocated 12MiB VRAM for framebuffer + offscreen pixmaps


and  everything work fine!

full log (with some home-made debug noise) will be attached
Comment 9 Andrew Randrianasulu 2008-05-03 12:15:15 UTC
Created attachment 16329 [details]
noisy log
Comment 10 Stuart Bennett 2009-01-19 13:53:23 UTC
Created attachment 22105 [details] [review]
patch which avoids passing sysmem addresses to the gpu when dest pixmap cannot be migrated into offscreen memory

I've reproduced this by hobbling my card to believe it only has 16Mb VRAM.  Under such a constraint the pNv->FB bo is only 8Mb, and with a larger virtual size it is used up with the viewable FB, leaving little (or no) room for EXA offscreen allocation (the viewable FB being pinned such that EXA can't migrate it out for obvious reasons).

Into this scenario the blitter comes with a large screen-sized destination pixmap.  The PutImage hook in nouveau_xv.c tries to ensure that the pixmap is in offscreen memory:

/* Ensure pixmap is in offscreen memory */
exaMoveInPixmap(ppix);

and later ppix is passed to OUT_PIXMAPl where a relocation is performed.  Sadly, the migration has failed (insufficient available space as the fullscreen pixmap is large) and a sys mem address is passed in at the relocation, and the GPU subsequently barfs.

The attached patch checks if the call to exaMoveInPixmap is successful by testing:
if (exaGetPixmapOffset(ppix) >= pNv->FB->size)
which gets the offset in memory of the pixmap from the start of pNv->FB->map; if the pixmap offset is less than the size of pNv->FB it is necessarily in offscreen memory.  This is the same test as applied in exaPixmapIsOffscreen, which only recently was exported as xorg api as exaDrawableIsOffscreen and hence cannot be used while maintaining compat with older xservers.  A call to the driver-supplied IsOffscreen function is included for the NOUVEAU_EXA_PIXMAPS case.  By returning BadAlloc here the XV client gets the error and no invalid memory locations reach the GPU.

After some further investigation whether this can/should be caught earlier, it seems to me it can't, as exaOffscreenAlloc is only called by exaDoMoveInPixmap which is the migration function.  In the event that exaOffscreenAlloc fails, exaDoMoveInPixmap simply returns, and as a void function no indication is given of the failure.  I'd welcome being told I've misunderstood this though.
Comment 11 Stephane Marchesin 2009-01-19 23:06:41 UTC
(In reply to comment #10)
> Created an attachment (id=22105) [details]
> patch which avoids passing sysmem addresses to the gpu when dest pixmap cannot
> be migrated into offscreen memory
> 
> I've reproduced this by hobbling my card to believe it only has 16Mb VRAM. 
> Under such a constraint the pNv->FB bo is only 8Mb, and with a larger virtual
> size it is used up with the viewable FB, leaving little (or no) room for EXA
> offscreen allocation (the viewable FB being pinned such that EXA can't migrate
> it out for obvious reasons).
> 
> Into this scenario the blitter comes with a large screen-sized destination
> pixmap.  The PutImage hook in nouveau_xv.c tries to ensure that the pixmap is
> in offscreen memory:
> 
> /* Ensure pixmap is in offscreen memory */
> exaMoveInPixmap(ppix);
> 
> and later ppix is passed to OUT_PIXMAPl where a relocation is performed. 
> Sadly, the migration has failed (insufficient available space as the fullscreen
> pixmap is large) and a sys mem address is passed in at the relocation, and the
> GPU subsequently barfs.
> 
> The attached patch checks if the call to exaMoveInPixmap is successful by
> testing:
> if (exaGetPixmapOffset(ppix) >= pNv->FB->size)
> which gets the offset in memory of the pixmap from the start of pNv->FB->map;
> if the pixmap offset is less than the size of pNv->FB it is necessarily in
> offscreen memory.  This is the same test as applied in exaPixmapIsOffscreen,
> which only recently was exported as xorg api as exaDrawableIsOffscreen and
> hence cannot be used while maintaining compat with older xservers.  A call to
> the driver-supplied IsOffscreen function is included for the
> NOUVEAU_EXA_PIXMAPS case.  By returning BadAlloc here the XV client gets the
> error and no invalid memory locations reach the GPU.
> 
> After some further investigation whether this can/should be caught earlier, it
> seems to me it can't, as exaOffscreenAlloc is only called by exaDoMoveInPixmap
> which is the migration function.  In the event that exaOffscreenAlloc fails,
> exaDoMoveInPixmap simply returns, and as a void function no indication is given
> of the failure.  I'd welcome being told I've misunderstood this though.
> 

Ok, indeed it seems we can't catch the failing allocation itself. But still, doing:
if (exaGetPixmapOffset(ppix) >= pNv->FB->size)
totally assumes that the FB is at the beggining of the EXA area. We've done such asumptions before and they always break in the end. Is there no other way ?
If all else fails, at least make it check agains FB->size and FB->offset.
Comment 12 Stuart Bennett 2009-03-06 06:53:33 UTC
(In reply to comment #11)
> Ok, indeed it seems we can't catch the failing allocation itself. But still,
> doing:
> if (exaGetPixmapOffset(ppix) >= pNv->FB->size)
> totally assumes that the FB is at the beggining of the EXA area. We've done
> such asumptions before and they always break in the end. Is there no other way
> ?
> If all else fails, at least make it check agains FB->size and FB->offset.

As I understand it pNv->FB includes the entire EXA area, not just the visible fb, exaGetPixmapOffset returns an offset relative to pExaScr->info->memoryBase (set to pNv->FB->map in nouveau_exa.c), so to see if a pixmap is in VRAM isn't testing if the (unsigned) offset is bigger than pNv->FB->size [*] correct, regardless of the positioning of the visible fb?

[*] or equivalently pNv->EXADriverPtr->memorySize which is perhaps more robust to changes in nouveau
Comment 13 Maarten Maathuis 2009-03-06 06:58:59 UTC
exaDrawableIsOffscreen() could also be used.

It became public api before the symbol visibility stuff (iirc), so you can probably get away by defining it if it's undefined.
Comment 14 Stephane Marchesin 2009-03-06 07:17:49 UTC
(In reply to comment #12)
> (In reply to comment #11)
> > Ok, indeed it seems we can't catch the failing allocation itself. But still,
> > doing:
> > if (exaGetPixmapOffset(ppix) >= pNv->FB->size)
> > totally assumes that the FB is at the beggining of the EXA area. We've done
> > such asumptions before and they always break in the end. Is there no other way
> > ?
> > If all else fails, at least make it check agains FB->size and FB->offset.
> 
> As I understand it pNv->FB includes the entire EXA area, not just the visible
> fb, exaGetPixmapOffset returns an offset relative to pExaScr->info->memoryBase
> (set to pNv->FB->map in nouveau_exa.c), so to see if a pixmap is in VRAM isn't
> testing if the (unsigned) offset is bigger than pNv->FB->size [*] correct,
> regardless of the positioning of the visible fb?
> 
> [*] or equivalently pNv->EXADriverPtr->memorySize which is perhaps more robust
> to changes in nouveau
> 

Hmm right. Yea I suppose pNv->EXADriverPtr->memorySize is a better choice.
Comment 15 Stuart Bennett 2009-03-06 12:09:55 UTC
Patch pushed as http://cgit.freedesktop.org/nouveau/xf86-video-nouveau/commit/?id=1e994400913bc656b34440df67aa105aa2b211c4 with pNv->EXADriverPtr->memorySize substitution.

I've not included any reference to exaDrawableIsOffscreen as it's a simple tested patch already, and when we go to NOUVEAU_EXA_PIXMAPS that part of the patch is irrelevant anyway.

For the memory available on the card, and the current memory manager that's as fixed as this is going to get, so closing.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.