| | 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 |