| 1 | /** @file |
| 2 | * |
| 3 | * VBox Remote Desktop Framebuffer |
| 4 | */ |
| 5 | |
| 6 | /* |
| 7 | * Copyright (C) 2010 Oracle Corporation |
| 8 | * |
| 9 | * This file is part of VirtualBox Open Source Edition (OSE), as |
| 10 | * available from http://www.virtualbox.org. This file is free software; |
| 11 | * you can redistribute it and/or modify it under the terms of the GNU |
| 12 | * General Public License (GPL) as published by the Free Software |
| 13 | * Foundation, in version 2 as it comes in the "COPYING" file of the |
| 14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the |
| 15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. |
| 16 | */ |
| 17 | |
| 18 | #include "Framebuffer.h" |
| 19 | |
| 20 | #include <VBox/com/com.h> |
| 21 | #include <VBox/com/array.h> |
| 22 | |
| 23 | #include <iprt/alloc.h> |
| 24 | |
| 25 | using namespace com; |
| 26 | |
| 27 | #define LOG_GROUP LOG_GROUP_GUI |
| 28 | #include <VBox/log.h> |
| 29 | |
| 30 | /* |
| 31 | * VRDP server frame buffer |
| 32 | */ |
| 33 | |
| 34 | #ifdef VBOX_WITH_XPCOM |
| 35 | #include <nsMemory.h> |
| 36 | NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDPFramebuffer, IFramebuffer) |
| 37 | NS_DECL_CLASSINFO(VRDPFramebuffer) |
| 38 | #endif |
| 39 | |
| 40 | VRDPFramebuffer::VRDPFramebuffer() |
| 41 | { |
| 42 | #if defined (RT_OS_WINDOWS) |
| 43 | refcnt = 0; |
| 44 | #endif /* RT_OS_WINDOWS */ |
| 45 | |
| 46 | mBuffer = NULL; |
| 47 | |
| 48 | RTCritSectInit (&m_CritSect); |
| 49 | |
| 50 | // start with a standard size |
| 51 | RequestResize(0, 0, |
| 52 | (ULONG) NULL, 0, 0, 640, 480, NULL); |
| 53 | } |
| 54 | |
| 55 | VRDPFramebuffer::~VRDPFramebuffer() |
| 56 | { |
| 57 | if (mBuffer) |
| 58 | { |
| 59 | RTMemFree (mBuffer); |
| 60 | } |
| 61 | |
| 62 | RTCritSectDelete (&m_CritSect); |
| 63 | } |
| 64 | |
| 65 | STDMETHODIMP VRDPFramebuffer::COMGETTER(Width)(ULONG *width) |
| 66 | { |
| 67 | if (!width) |
| 68 | return E_INVALIDARG; |
| 69 | *width = mWidth; |
| 70 | return S_OK; |
| 71 | } |
| 72 | |
| 73 | STDMETHODIMP VRDPFramebuffer::COMGETTER(Height)(ULONG *height) |
| 74 | { |
| 75 | if (!height) |
| 76 | return E_INVALIDARG; |
| 77 | *height = mHeight; |
| 78 | return S_OK; |
| 79 | } |
| 80 | |
| 81 | STDMETHODIMP VRDPFramebuffer::Lock() |
| 82 | { |
| 83 | RTCritSectEnter (&m_CritSect); |
| 84 | return S_OK; |
| 85 | } |
| 86 | |
| 87 | STDMETHODIMP VRDPFramebuffer::Unlock() |
| 88 | { |
| 89 | RTCritSectLeave (&m_CritSect); |
| 90 | return S_OK; |
| 91 | } |
| 92 | |
| 93 | STDMETHODIMP VRDPFramebuffer::COMGETTER(Address)(BYTE **address) |
| 94 | { |
| 95 | if (!address) |
| 96 | return E_INVALIDARG; |
| 97 | *address = mScreen; |
| 98 | return S_OK; |
| 99 | } |
| 100 | |
| 101 | STDMETHODIMP VRDPFramebuffer::COMGETTER(BitsPerPixel)(ULONG *bitsPerPixel) |
| 102 | { |
| 103 | if (!bitsPerPixel) |
| 104 | return E_INVALIDARG; |
| 105 | *bitsPerPixel = mBitsPerPixel; |
| 106 | return S_OK; |
| 107 | } |
| 108 | |
| 109 | STDMETHODIMP VRDPFramebuffer::COMGETTER(BytesPerLine)(ULONG *bytesPerLine) |
| 110 | { |
| 111 | if (!bytesPerLine) |
| 112 | return E_INVALIDARG; |
| 113 | *bytesPerLine = mBytesPerLine; |
| 114 | return S_OK; |
| 115 | } |
| 116 | |
| 117 | STDMETHODIMP VRDPFramebuffer::COMGETTER(PixelFormat) (ULONG *pixelFormat) |
| 118 | { |
| 119 | if (!pixelFormat) |
| 120 | return E_POINTER; |
| 121 | *pixelFormat = mPixelFormat; |
| 122 | return S_OK; |
| 123 | } |
| 124 | |
| 125 | STDMETHODIMP VRDPFramebuffer::COMGETTER(UsesGuestVRAM) (BOOL *usesGuestVRAM) |
| 126 | { |
| 127 | if (!usesGuestVRAM) |
| 128 | return E_POINTER; |
| 129 | *usesGuestVRAM = mUsesGuestVRAM; |
| 130 | return S_OK; |
| 131 | } |
| 132 | |
| 133 | STDMETHODIMP VRDPFramebuffer::COMGETTER(HeightReduction) (ULONG *heightReduction) |
| 134 | { |
| 135 | if (!heightReduction) |
| 136 | return E_POINTER; |
| 137 | /* no reduction at all */ |
| 138 | *heightReduction = 0; |
| 139 | return S_OK; |
| 140 | } |
| 141 | |
| 142 | STDMETHODIMP VRDPFramebuffer::COMGETTER(Overlay) (IFramebufferOverlay **aOverlay) |
| 143 | { |
| 144 | if (!aOverlay) |
| 145 | return E_POINTER; |
| 146 | /* overlays are not yet supported */ |
| 147 | *aOverlay = 0; |
| 148 | return S_OK; |
| 149 | } |
| 150 | |
| 151 | STDMETHODIMP VRDPFramebuffer::COMGETTER(WinId) (LONG64 *winId) |
| 152 | { |
| 153 | if (!winId) |
| 154 | return E_POINTER; |
| 155 | *winId = 0; |
| 156 | return S_OK; |
| 157 | } |
| 158 | |
| 159 | STDMETHODIMP VRDPFramebuffer::COMGETTER(Capabilities)(ComSafeArrayOut(FramebufferCapabilities_T, aCapabilities)) |
| 160 | { |
| 161 | if (ComSafeArrayOutIsNull(aCapabilities)) |
| 162 | return E_POINTER; |
| 163 | |
| 164 | com::SafeArray<FramebufferCapabilities_T> caps; |
| 165 | caps.resize(1); |
| 166 | caps[0] = FramebufferCapabilities_UpdateImage; |
| 167 | caps.detachTo(ComSafeArrayOutArg(aCapabilities)); |
| 168 | return S_OK; |
| 169 | } |
| 170 | |
| 171 | STDMETHODIMP VRDPFramebuffer::NotifyUpdate(ULONG x, ULONG y, |
| 172 | ULONG w, ULONG h) |
| 173 | { |
| 174 | return S_OK; |
| 175 | } |
| 176 | |
| 177 | STDMETHODIMP VRDPFramebuffer::NotifyUpdateImage(ULONG aX, |
| 178 | ULONG aY, |
| 179 | ULONG aWidth, |
| 180 | ULONG aHeight, |
| 181 | ComSafeArrayIn(BYTE, aImage)) |
| 182 | { |
| 183 | return S_OK; |
| 184 | } |
| 185 | |
| 186 | STDMETHODIMP VRDPFramebuffer::NotifyChange(ULONG aScreenId, |
| 187 | ULONG aXOrigin, |
| 188 | ULONG aYOrigin, |
| 189 | ULONG aWidth, |
| 190 | ULONG aHeight) |
| 191 | { |
| 192 | return S_OK; |
| 193 | } |
| 194 | |
| 195 | STDMETHODIMP VRDPFramebuffer::RequestResize(ULONG aScreenId, ULONG pixelFormat, BYTE *vram, |
| 196 | ULONG bitsPerPixel, ULONG bytesPerLine, |
| 197 | ULONG w, ULONG h, |
| 198 | BOOL *finished) |
| 199 | { |
| 200 | /* Agree to requested format for LFB modes and use guest VRAM directly, thus avoiding |
| 201 | * unnecessary memcpy in VGA device. |
| 202 | */ |
| 203 | |
| 204 | Log(("pixelFormat = %08X, vram = %p, bpp = %d, bpl = 0x%08X, %dx%d\n", |
| 205 | pixelFormat, vram, bitsPerPixel, bytesPerLine, w, h)); |
| 206 | |
| 207 | /* Free internal buffer. */ |
| 208 | if (mBuffer) |
| 209 | { |
| 210 | RTMemFree (mBuffer); |
| 211 | mBuffer = NULL; |
| 212 | } |
| 213 | |
| 214 | mUsesGuestVRAM = FALSE; |
| 215 | |
| 216 | mWidth = w; |
| 217 | mHeight = h; |
| 218 | |
| 219 | if (pixelFormat == BitmapFormat_BGR) |
| 220 | { |
| 221 | switch (bitsPerPixel) |
| 222 | { |
| 223 | case 32: |
| 224 | case 24: |
| 225 | case 16: |
| 226 | mUsesGuestVRAM = TRUE; |
| 227 | break; |
| 228 | |
| 229 | default: |
| 230 | break; |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | if (mUsesGuestVRAM) |
| 235 | { |
| 236 | mScreen = vram; |
| 237 | mBitsPerPixel = bitsPerPixel; |
| 238 | mBytesPerLine = bytesPerLine; |
| 239 | mPixelFormat = BitmapFormat_BGR; |
| 240 | |
| 241 | Log (("Using guest VRAM directly, %d BPP\n", mBitsPerPixel)); |
| 242 | } |
| 243 | else |
| 244 | { |
| 245 | mBitsPerPixel = 32; |
| 246 | mBytesPerLine = w * 4; /* Here we have 32 BPP */ |
| 247 | |
| 248 | if (mBytesPerLine > 0 && h > 0) /* Check for nul dimensions. */ |
| 249 | { |
| 250 | mBuffer = RTMemAllocZ(mBytesPerLine * h); |
| 251 | } |
| 252 | |
| 253 | mScreen = (uint8_t *)mBuffer; |
| 254 | |
| 255 | Log(("Using internal buffer, %d BPP\n", mBitsPerPixel)); |
| 256 | } |
| 257 | |
| 258 | if (!mScreen) |
| 259 | { |
| 260 | Log(("No screen. BPP = %d, w = %d, h = %d!!!\n", mBitsPerPixel, w, h)); |
| 261 | |
| 262 | /* Just reset everything. */ |
| 263 | mPixelFormat = 0; |
| 264 | |
| 265 | mWidth = 0; |
| 266 | mHeight = 0; |
| 267 | mBitsPerPixel = 0; |
| 268 | mBytesPerLine = 0; |
| 269 | mUsesGuestVRAM = FALSE; |
| 270 | } |
| 271 | |
| 272 | /* Inform the caller that the operation was successful. */ |
| 273 | |
| 274 | if (finished) |
| 275 | *finished = TRUE; |
| 276 | |
| 277 | return S_OK; |
| 278 | } |
| 279 | |
| 280 | /** |
| 281 | * Returns whether we like the given video mode. |
| 282 | * |
| 283 | * @returns COM status code |
| 284 | * @param width video mode width in pixels |
| 285 | * @param height video mode height in pixels |
| 286 | * @param bpp video mode bit depth in bits per pixel |
| 287 | * @param supported pointer to result variable |
| 288 | */ |
| 289 | STDMETHODIMP VRDPFramebuffer::VideoModeSupported(ULONG width, ULONG height, ULONG bpp, BOOL *supported) |
| 290 | { |
| 291 | if (!supported) |
| 292 | return E_POINTER; |
| 293 | *supported = TRUE; |
| 294 | return S_OK; |
| 295 | } |
| 296 | |
| 297 | STDMETHODIMP VRDPFramebuffer::GetVisibleRegion(BYTE *aRectangles, ULONG aCount, |
| 298 | ULONG *aCountCopied) |
| 299 | { |
| 300 | PRTRECT rects = (PRTRECT)aRectangles; |
| 301 | |
| 302 | if (!rects) |
| 303 | return E_POINTER; |
| 304 | |
| 305 | /// @todo |
| 306 | |
| 307 | NOREF(aCount); |
| 308 | NOREF(aCountCopied); |
| 309 | |
| 310 | return S_OK; |
| 311 | } |
| 312 | |
| 313 | STDMETHODIMP VRDPFramebuffer::SetVisibleRegion(BYTE *aRectangles, ULONG aCount) |
| 314 | { |
| 315 | PRTRECT rects = (PRTRECT)aRectangles; |
| 316 | |
| 317 | if (!rects) |
| 318 | return E_POINTER; |
| 319 | |
| 320 | /// @todo |
| 321 | |
| 322 | NOREF(aCount); |
| 323 | |
| 324 | return S_OK; |
| 325 | } |
| 326 | |
| 327 | STDMETHODIMP VRDPFramebuffer::ProcessVHWACommand(BYTE *pCommand) |
| 328 | { |
| 329 | return E_NOTIMPL; |
| 330 | } |
| 331 | |
| 332 | STDMETHODIMP VRDPFramebuffer::Notify3DEvent(ULONG uType, ComSafeArrayIn(BYTE, aData)) |
| 333 | { |
| 334 | return E_NOTIMPL; |
| 335 | } |
| 336 | No newline at end of file |