The BIOS.DisplayString function 13h cannot display a background color other than black. This is especially true in the 256-color video mode where the attribute in BL can no longer express both a foreground and a background color since the foreground color setting already occupies the whole 8 bits.
I have written a procedure that can display an ASCIIZ string on the 256-color screen using one of 16 foreground colors and one of 16 background colors. The string is unlimited in how long it is or in what it can contain (bell, backspace, tab, linefeed, carriage return).
Eventhough the code uses BIOS for everything, DOSBox paints the whole screen in a jiffy. If this is still not fast enough, then fetch a pointer to the font and write directly to the screen at A000:0000. You would also have to manage the cursor yourself. I'm sure it would be faster but I doubt it would matter...
ORG 256
mov ax, 0013h ; BIOS.SetVideo 320x200 256-color graphics screen
int 10h
mov si, msg1
mov bl, 0E2h ; GreenOnYellow
call WriteStringWithAttributeMode19
mov si, msg2
mov bl, 0F0h ; BlackOnWhite
call WriteStringWithAttributeMode19
mov ah, 00h ; BIOS.GetKeystroke
int 16h ; -> AX
mov ax, 0003h ; BIOS.SetVideo 80x25 16-color text screen
int 10h
ret
; ---------------------------
msg1: db 'This is a colourful text', 13, 10
db ' written on two lines ', 13, 10, 0
msg2: db '------------------------', 13, 10
db 879 dup 'Q', 0
; ---------------------------
; IN (bl,ds:si) OUT ()
WriteStringWithAttributeMode19:
pusha
mov bh, 0 ; Display page 0
mov bp, bx
jmps .d
.a: cmp al, 9
je .Tab
cmp al, 13
ja .b
mov cx, 1101_1010_0111_1111b
bt cx, ax
jnc .c ; 7,8,10,13 don't need the color
.b: mov bx, bp
mov dl, bl
shr dl, 4 ; Get background color (high nibble)
and bl, 15 ; Get foreground color (low nibble)
xor bl, dl
mov ah, 0Eh
int 10h ; BIOS.Teletype
mov ah, 03h
int 10h ; BIOS.GetCursor -> CX DX
dec dl ; Column is [0,39]
jns :1
mov dl, 39
dec dh
:1: movzx cx, dl ; Column -> X
shl cx, 3
movzx dx, dh ; Row -> Y
shl dx, 3
mov bx, bp
shr bl, 4 ; Get background color (high nibble)
:2: mov ah, 0Dh ; BIOS.ReadPixel
int 10h ; -> AL
xor al, bl
mov ah, 0Ch ; BIOS.WritePixel
int 10h
inc cx ; X++
test cx, 7
jnz :2
sub cx, 8
inc dx ; Y++
test dx, 7
jnz :2
jmp .d
.c: mov ah, 0Eh
int 10h ; BIOS.Teletype
.d: lodsb
test al, al
jnz .a
popa
ret
.Tab: mov cx, 1 ; Start displaying colored space(s)
mov bx, bp
shr bl, 4 ; Get background color
mov ax, 0EDBh ; ASCII DBh is full block character
int 10h ; BIOS.Teletype
mov ah, 03h
int 10h ; BIOS.GetCursor -> CX DX
test dl, 7
jnz .Tab ; Column not yet multiple of 8
jmps .d
; ----------------------------
You can find a similar code for the 16-color graphics screens in the WriteStringWithAttributeGVM procedure which is part of Displaying characters with DOS or BIOS.