<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

/*************************** -*- Mod: C++ -*- ******************************
  SSLSNIConfig.cc
   Created On      : 05/02/2017

   Description:
   SNI based Configuration in ATS
 ****************************************************************************/

#include "P_SSLSNI.h"
#include "ts/Diags.h"
#include "ts/SimpleTokenizer.h"
#include "P_SSLConfig.h"
#include "ts/ink_memory.h"

#define SNI_NAME_TAG "dest_host"
#define SNI_ACTION_TAG "action"
#define SNI_PARAM_TAG "param"

static ConfigUpdateHandler<SNIConfig> *sniConfigUpdate;
struct NetAccept;
extern std::vector<NetAccept *> naVec;
Map<int, SSLNextProtocolSet *> snpsMap;
extern TunnelHashMap TunnelMap;
NextHopProperty::NextHopProperty()
{
}

NextHopProperty *
SNIConfigParams::getPropertyConfig(cchar *servername) const
{
  NextHopProperty *nps = nullptr;
  nps                  = next_hop_table.get(servername);
  if (!nps)
    nps = wild_next_hop_table.get(servername);
  return nps;
}

void
SNIConfigParams::loadSNIConfig()
{
  for (auto item : L_sni.items) {
    actionVector *aiVec = new actionVector();
    Debug("ssl", "name: %s", item.fqdn.data());
    cchar *servername = item.fqdn.data();
    ats_wildcard_matcher w_Matcher;
    auto wildcard = w_Matcher.match(servername);

    // set SNI based actions to be called in the ssl_servername_only callback
    auto ai1 = new DisableH2();
    aiVec->push_back(ai1);
    auto ai2 = new VerifyClient(item.verify_client_level);
    aiVec->push_back(ai2);
    sni_action_map.put(ats_strdup(servername), aiVec);

    if (item.tunnel_destination.length()) {
      TunnelMap.emplace(item.fqdn.data(), item.tunnel_destination);
    }

    // set the next hop properties
    SSLConfig::scoped_config params;
    auto clientCTX  = params->getCTX(servername);
    cchar *certFile = item.client_cert.data();
    if (!clientCTX && certFile) {
      clientCTX = params->getNewCTX(certFile);
      params->InsertCTX(certFile, clientCTX);
    }
    NextHopProperty *nps = new NextHopProperty();
    nps->name            = ats_strdup(servername);
    nps->verifyLevel     = item.verify_origin_server;
    nps->ctx             = clientCTX;
    if (wildcard)
      wild_next_hop_table.put(nps->name, nps);
    else
      next_hop_table.put(nps->name, nps);
  } // end for
}

int SNIConfig::configid = 0;
/*definition of member functions of SNIConfigParams*/
SNIConfigParams::SNIConfigParams()
{
}

actionVector *
SNIConfigParams::get(cchar *servername) const
{
  auto actionVec = sni_action_map.get(servername);
  if (!actionVec)
    actionVec = wild_sni_action_map.get(servername);
  return actionVec;
}

void
SNIConfigParams::printSNImap() const
{
  Vec<cchar *> keys;
  sni_action_map.get_keys(keys);
  for (size_t i = 0; i < keys.length(); i++) {
    Debug("ssl", "Domain name in the map %s: # of registered action items %lu", (char *)keys.get(i),
          sni_action_map.get(keys.get(i))->size());
  }
}

int
SNIConfigParams::Initialize()
{
  sni_filename = ats_stringdup(RecConfigReadConfigPath("proxy.config.ssl.servername.filename"));
  lua_State *L = lua_open(); /* opens Lua */
  luaL_openlibs(L);
  luaL_loadfile(L, sni_filename);
  lua_pcall(L, 0, 0, 0);
  L_sni.loader(L);
  loadSNIConfig();
  return 0;
}

void
SNIConfigParams::cleanup()
{
  Vec<cchar *> keys;
  sni_action_map.get_keys(keys);
  for (int i = keys.length() - 1; i >= 0; i--) {
    auto actionVec = sni_action_map.get(keys.get(i));
    for (auto &ai : *actionVec)
      delete ai;

    actionVec->clear();
  }
  keys.free_and_clear();

  wild_sni_action_map.get_keys(keys);
  for (int i = keys.length() - 1; i >= 0; i--) {
    auto actionVec = wild_sni_action_map.get(keys.get(i));
    for (auto &ai : *actionVec)
      delete ai;

    actionVec->clear();
  }
  keys.free_and_clear();

  next_hop_table.get_keys(keys);
  for (int i = 0; i < static_cast<int>(keys.length()); i++) {
    auto *nps = next_hop_table.get(keys.get(i));
    delete (nps);
  }
  keys.free_and_clear();

  wild_next_hop_table.get_keys(keys);
  for (int i = 0; static_cast<int>(keys.length()); i++) {
    auto *nps = wild_next_hop_table.get(keys.get(i));
    delete (nps);
  }
  keys.free_and_clear();
}

SNIConfigParams::~SNIConfigParams()
{
  cleanup();
}

/*definition of member functions of SNIConfig*/
void
SNIConfig::startup()
{
  sniConfigUpdate = new ConfigUpdateHandler<SNIConfig>();
  sniConfigUpdate->attach("proxy.config.ssl.servername.filename");
  reconfigure();
}

void
SNIConfig::cloneProtoSet()
{
  for (auto na : naVec) {
    if (na->snpa) {
      auto snps = na->snpa->cloneProtoSet();
      snps->unregisterEndpoint(TS_ALPN_PROTOCOL_HTTP_2_0, nullptr);
      snpsMap.put(na->id, snps);
    }
  }
}

void
SNIConfig::reconfigure()
{
  SNIConfigParams *params = new SNIConfigParams;

  params->Initialize();
  configid = configProcessor.set(configid, params);
}

SNIConfigParams *
SNIConfig::acquire()
{
  return (SNIConfigParams *)configProcessor.get(configid);
}

void
SNIConfig::release(SNIConfigParams *params)
{
  configProcessor.release(configid, params);
}
<commit_msg>coverity 1382799, 1382796: Unchecked return value<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

/*************************** -*- Mod: C++ -*- ******************************
  SSLSNIConfig.cc
   Created On      : 05/02/2017

   Description:
   SNI based Configuration in ATS
 ****************************************************************************/

#include "P_SSLSNI.h"
#include "ts/Diags.h"
#include "ts/SimpleTokenizer.h"
#include "P_SSLConfig.h"
#include "ts/ink_memory.h"

#define SNI_NAME_TAG "dest_host"
#define SNI_ACTION_TAG "action"
#define SNI_PARAM_TAG "param"

static ConfigUpdateHandler<SNIConfig> *sniConfigUpdate;
struct NetAccept;
extern std::vector<NetAccept *> naVec;
Map<int, SSLNextProtocolSet *> snpsMap;
extern TunnelHashMap TunnelMap;
NextHopProperty::NextHopProperty()
{
}

NextHopProperty *
SNIConfigParams::getPropertyConfig(cchar *servername) const
{
  NextHopProperty *nps = nullptr;
  nps                  = next_hop_table.get(servername);
  if (!nps)
    nps = wild_next_hop_table.get(servername);
  return nps;
}

void
SNIConfigParams::loadSNIConfig()
{
  for (auto item : L_sni.items) {
    actionVector *aiVec = new actionVector();
    Debug("ssl", "name: %s", item.fqdn.data());
    cchar *servername = item.fqdn.data();
    ats_wildcard_matcher w_Matcher;
    auto wildcard = w_Matcher.match(servername);

    // set SNI based actions to be called in the ssl_servername_only callback
    auto ai1 = new DisableH2();
    aiVec->push_back(ai1);
    auto ai2 = new VerifyClient(item.verify_client_level);
    aiVec->push_back(ai2);
    sni_action_map.put(ats_strdup(servername), aiVec);

    if (item.tunnel_destination.length()) {
      TunnelMap.emplace(item.fqdn.data(), item.tunnel_destination);
    }

    // set the next hop properties
    SSLConfig::scoped_config params;
    auto clientCTX  = params->getCTX(servername);
    cchar *certFile = item.client_cert.data();
    if (!clientCTX && certFile) {
      clientCTX = params->getNewCTX(certFile);
      params->InsertCTX(certFile, clientCTX);
    }
    NextHopProperty *nps = new NextHopProperty();
    nps->name            = ats_strdup(servername);
    nps->verifyLevel     = item.verify_origin_server;
    nps->ctx             = clientCTX;
    if (wildcard)
      wild_next_hop_table.put(nps->name, nps);
    else
      next_hop_table.put(nps->name, nps);
  } // end for
}

int SNIConfig::configid = 0;
/*definition of member functions of SNIConfigParams*/
SNIConfigParams::SNIConfigParams()
{
}

actionVector *
SNIConfigParams::get(cchar *servername) const
{
  auto actionVec = sni_action_map.get(servername);
  if (!actionVec)
    actionVec = wild_sni_action_map.get(servername);
  return actionVec;
}

void
SNIConfigParams::printSNImap() const
{
  Vec<cchar *> keys;
  sni_action_map.get_keys(keys);
  for (size_t i = 0; i < keys.length(); i++) {
    Debug("ssl", "Domain name in the map %s: # of registered action items %lu", (char *)keys.get(i),
          sni_action_map.get(keys.get(i))->size());
  }
}

int
SNIConfigParams::Initialize()
{
  sni_filename = ats_stringdup(RecConfigReadConfigPath("proxy.config.ssl.servername.filename"));
  struct stat sbuf;
  if (stat(sni_filename, &sbuf) == -1 && errno == ENOENT) {
    Warning("Loading SNI configuration - filename: %s doesn't exist", sni_filename);
    return 1;
  }

  lua_State *L = lua_open(); /* opens Lua */
  luaL_openlibs(L);
  if (luaL_loadfile(L, sni_filename)) {
    Error("Loading SNI configuration - luaL_loadfile: %s", lua_tostring(L, -1));
    lua_pop(L, 1);
    return 1;
  }

  if (lua_pcall(L, 0, 0, 0)) {
    Error("Loading SNI configuration - luap_pcall: %s failed: %s", sni_filename, lua_tostring(L, -1));
    lua_pop(L, 1);
    return 1;
  }

  L_sni.loader(L);
  loadSNIConfig();
  return 0;
}

void
SNIConfigParams::cleanup()
{
  Vec<cchar *> keys;
  sni_action_map.get_keys(keys);
  for (int i = keys.length() - 1; i >= 0; i--) {
    auto actionVec = sni_action_map.get(keys.get(i));
    for (auto &ai : *actionVec)
      delete ai;

    actionVec->clear();
  }
  keys.free_and_clear();

  wild_sni_action_map.get_keys(keys);
  for (int i = keys.length() - 1; i >= 0; i--) {
    auto actionVec = wild_sni_action_map.get(keys.get(i));
    for (auto &ai : *actionVec)
      delete ai;

    actionVec->clear();
  }
  keys.free_and_clear();

  next_hop_table.get_keys(keys);
  for (int i = 0; i < static_cast<int>(keys.length()); i++) {
    auto *nps = next_hop_table.get(keys.get(i));
    delete (nps);
  }
  keys.free_and_clear();

  wild_next_hop_table.get_keys(keys);
  for (int i = 0; static_cast<int>(keys.length()); i++) {
    auto *nps = wild_next_hop_table.get(keys.get(i));
    delete (nps);
  }
  keys.free_and_clear();
}

SNIConfigParams::~SNIConfigParams()
{
  cleanup();
}

/*definition of member functions of SNIConfig*/
void
SNIConfig::startup()
{
  sniConfigUpdate = new ConfigUpdateHandler<SNIConfig>();
  sniConfigUpdate->attach("proxy.config.ssl.servername.filename");
  reconfigure();
}

void
SNIConfig::cloneProtoSet()
{
  for (auto na : naVec) {
    if (na->snpa) {
      auto snps = na->snpa->cloneProtoSet();
      snps->unregisterEndpoint(TS_ALPN_PROTOCOL_HTTP_2_0, nullptr);
      snpsMap.put(na->id, snps);
    }
  }
}

void
SNIConfig::reconfigure()
{
  SNIConfigParams *params = new SNIConfigParams;

  params->Initialize();
  configid = configProcessor.set(configid, params);
}

SNIConfigParams *
SNIConfig::acquire()
{
  return (SNIConfigParams *)configProcessor.get(configid);
}

void
SNIConfig::release(SNIConfigParams *params)
{
  configProcessor.release(configid, params);
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/video_engine/vie_base_impl.h"

#include <sstream>
#include <string>

#include "webrtc/engine_configurations.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_processing/main/interface/video_processing.h"
#include "webrtc/modules/video_render/include/video_render.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/video_engine/include/vie_errors.h"
#include "webrtc/video_engine/vie_channel.h"
#include "webrtc/video_engine/vie_channel_manager.h"
#include "webrtc/video_engine/vie_defines.h"
#include "webrtc/video_engine/vie_encoder.h"
#include "webrtc/video_engine/vie_impl.h"
#include "webrtc/video_engine/vie_input_manager.h"
#include "webrtc/video_engine/vie_shared_data.h"

namespace webrtc {

ViEBase* ViEBase::GetInterface(VideoEngine* video_engine) {
  if (!video_engine) {
    return NULL;
  }
  VideoEngineImpl* vie_impl = static_cast<VideoEngineImpl*>(video_engine);
  ViEBaseImpl* vie_base_impl = vie_impl;
  (*vie_base_impl)++;  // Increase ref count.

  return vie_base_impl;
}

int ViEBaseImpl::Release() {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_.instance_id(),
               "ViEBase::Release()");
  (*this)--;  // Decrease ref count.

  int32_t ref_count = GetCount();
  if (ref_count < 0) {
    WEBRTC_TRACE(kTraceWarning, kTraceVideo, shared_data_.instance_id(),
                 "ViEBase release too many times");
    shared_data_.SetLastError(kViEAPIDoesNotExist);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, shared_data_.instance_id(),
               "ViEBase reference count: %d", ref_count);
  return ref_count;
}

ViEBaseImpl::ViEBaseImpl(const Config& config)
    : shared_data_(config) {
  WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_.instance_id(),
               "ViEBaseImpl::ViEBaseImpl() Ctor");
}

ViEBaseImpl::~ViEBaseImpl() {
  WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_.instance_id(),
               "ViEBaseImpl::ViEBaseImpl() Dtor");
}

int ViEBaseImpl::Init() {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_.instance_id(),
               "Init");
  return 0;
}

int ViEBaseImpl::SetVoiceEngine(VoiceEngine* voice_engine) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s", __FUNCTION__);
  if (shared_data_.channel_manager()->SetVoiceEngine(voice_engine) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::CreateChannel(int& video_channel) {  // NOLINT
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s", __FUNCTION__);
  if (shared_data_.channel_manager()->CreateChannel(&video_channel) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not create channel", __FUNCTION__);
    video_channel = -1;
    shared_data_.SetLastError(kViEBaseChannelCreationFailed);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel created: %d", __FUNCTION__, video_channel);
  return 0;
}

int ViEBaseImpl::CreateChannel(int& video_channel,  // NOLINT
                               int original_channel) {
  return CreateChannel(video_channel, original_channel, true);
}

int ViEBaseImpl::CreateReceiveChannel(int& video_channel,  // NOLINT
                                      int original_channel) {
  return CreateChannel(video_channel, original_channel, false);
}

int ViEBaseImpl::DeleteChannel(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  {
    ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
    ViEChannel* vie_channel = cs.Channel(video_channel);
    if (!vie_channel) {
      WEBRTC_TRACE(kTraceError, kTraceVideo,
                   ViEId(shared_data_.instance_id()),
                   "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
      shared_data_.SetLastError(kViEBaseInvalidChannelId);
      return -1;
    }

    // Deregister the ViEEncoder if no other channel is using it.
    ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    if (cs.ChannelUsingViEEncoder(video_channel) == false) {
      ViEInputManagerScoped is(*(shared_data_.input_manager()));
      ViEFrameProviderBase* provider = is.FrameProvider(vie_encoder);
      if (provider) {
        provider->DeregisterFrameCallback(vie_encoder);
      }
    }
  }

  if (shared_data_.channel_manager()->DeleteChannel(video_channel) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not delete channel %d", __FUNCTION__,
                 video_channel);
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel deleted: %d", __FUNCTION__, video_channel);
  return 0;
}

int ViEBaseImpl::ConnectAudioChannel(const int video_channel,
                                     const int audio_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(video_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->ConnectVoiceChannel(video_channel,
                                                          audio_channel) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::DisconnectAudioChannel(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(video_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->DisconnectVoiceChannel(
      video_channel) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StartSend(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  assert(vie_encoder != NULL);
  if (vie_encoder->Owner() != video_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "Can't start ssend on a receive only channel.");
    shared_data_.SetLastError(kViEBaseReceiveOnlyChannel);
    return -1;
  }

  // Pause and trigger a key frame.
  vie_encoder->Pause();
  int32_t error = vie_channel->StartSend();
  if (error != 0) {
    vie_encoder->Restart();
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Could not start sending on channel %d", __FUNCTION__,
                 video_channel);
    if (error == kViEBaseAlreadySending) {
      shared_data_.SetLastError(kViEBaseAlreadySending);
    }
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  vie_encoder->SendKeyFrame();
  vie_encoder->Restart();
  return 0;
}

int ViEBaseImpl::StopSend(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  int32_t error = vie_channel->StopSend();
  if (error != 0) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Could not stop sending on channel %d", __FUNCTION__,
                 video_channel);
    if (error == kViEBaseNotSending) {
      shared_data_.SetLastError(kViEBaseNotSending);
    } else {
      shared_data_.SetLastError(kViEBaseUnknownError);
    }
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StartReceive(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }
  if (vie_channel->StartReceive() != 0) {
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StopReceive(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }
  if (vie_channel->StopReceive() != 0) {
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::GetVersion(char version[1024]) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "GetVersion(version=?)");
  assert(kViEVersionMaxMessageSize == 1024);
  if (!version) {
    shared_data_.SetLastError(kViEBaseInvalidArgument);
    return -1;
  }

  // Add WebRTC Version.
  std::stringstream version_stream;
  version_stream << "VideoEngine 3.33.0" << std::endl;

  // Add build info.
  version_stream << "Build: svn:" << WEBRTC_SVNREVISION << " " << BUILDINFO
                 << std::endl;

#ifdef WEBRTC_EXTERNAL_TRANSPORT
  version_stream << "External transport build" << std::endl;
#endif
  int version_length = version_stream.tellp();
  assert(version_length < 1024);
  memcpy(version, version_stream.str().c_str(), version_length);
  version[version_length] = '\0';

  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo,
               ViEId(shared_data_.instance_id()), "GetVersion() => %s",
               version);
  return 0;
}

int ViEBaseImpl::LastError() {
  return shared_data_.LastErrorInternal();
}

int ViEBaseImpl::CreateChannel(int& video_channel,  // NOLINT
                               int original_channel, bool sender) {
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(original_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s - original_channel does not exist.", __FUNCTION__,
                 shared_data_.instance_id());
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->CreateChannel(&video_channel,
                                                    original_channel,
                                                    sender) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not create channel", __FUNCTION__);
    video_channel = -1;
    shared_data_.SetLastError(kViEBaseChannelCreationFailed);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel created: %d", __FUNCTION__, video_channel);
  return 0;
}

}  // namespace webrtc
<commit_msg>Update version number to 3.34<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/video_engine/vie_base_impl.h"

#include <sstream>
#include <string>

#include "webrtc/engine_configurations.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_processing/main/interface/video_processing.h"
#include "webrtc/modules/video_render/include/video_render.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/video_engine/include/vie_errors.h"
#include "webrtc/video_engine/vie_channel.h"
#include "webrtc/video_engine/vie_channel_manager.h"
#include "webrtc/video_engine/vie_defines.h"
#include "webrtc/video_engine/vie_encoder.h"
#include "webrtc/video_engine/vie_impl.h"
#include "webrtc/video_engine/vie_input_manager.h"
#include "webrtc/video_engine/vie_shared_data.h"

namespace webrtc {

ViEBase* ViEBase::GetInterface(VideoEngine* video_engine) {
  if (!video_engine) {
    return NULL;
  }
  VideoEngineImpl* vie_impl = static_cast<VideoEngineImpl*>(video_engine);
  ViEBaseImpl* vie_base_impl = vie_impl;
  (*vie_base_impl)++;  // Increase ref count.

  return vie_base_impl;
}

int ViEBaseImpl::Release() {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_.instance_id(),
               "ViEBase::Release()");
  (*this)--;  // Decrease ref count.

  int32_t ref_count = GetCount();
  if (ref_count < 0) {
    WEBRTC_TRACE(kTraceWarning, kTraceVideo, shared_data_.instance_id(),
                 "ViEBase release too many times");
    shared_data_.SetLastError(kViEAPIDoesNotExist);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, shared_data_.instance_id(),
               "ViEBase reference count: %d", ref_count);
  return ref_count;
}

ViEBaseImpl::ViEBaseImpl(const Config& config)
    : shared_data_(config) {
  WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_.instance_id(),
               "ViEBaseImpl::ViEBaseImpl() Ctor");
}

ViEBaseImpl::~ViEBaseImpl() {
  WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_.instance_id(),
               "ViEBaseImpl::ViEBaseImpl() Dtor");
}

int ViEBaseImpl::Init() {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_.instance_id(),
               "Init");
  return 0;
}

int ViEBaseImpl::SetVoiceEngine(VoiceEngine* voice_engine) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s", __FUNCTION__);
  if (shared_data_.channel_manager()->SetVoiceEngine(voice_engine) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::CreateChannel(int& video_channel) {  // NOLINT
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s", __FUNCTION__);
  if (shared_data_.channel_manager()->CreateChannel(&video_channel) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not create channel", __FUNCTION__);
    video_channel = -1;
    shared_data_.SetLastError(kViEBaseChannelCreationFailed);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel created: %d", __FUNCTION__, video_channel);
  return 0;
}

int ViEBaseImpl::CreateChannel(int& video_channel,  // NOLINT
                               int original_channel) {
  return CreateChannel(video_channel, original_channel, true);
}

int ViEBaseImpl::CreateReceiveChannel(int& video_channel,  // NOLINT
                                      int original_channel) {
  return CreateChannel(video_channel, original_channel, false);
}

int ViEBaseImpl::DeleteChannel(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  {
    ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
    ViEChannel* vie_channel = cs.Channel(video_channel);
    if (!vie_channel) {
      WEBRTC_TRACE(kTraceError, kTraceVideo,
                   ViEId(shared_data_.instance_id()),
                   "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
      shared_data_.SetLastError(kViEBaseInvalidChannelId);
      return -1;
    }

    // Deregister the ViEEncoder if no other channel is using it.
    ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    if (cs.ChannelUsingViEEncoder(video_channel) == false) {
      ViEInputManagerScoped is(*(shared_data_.input_manager()));
      ViEFrameProviderBase* provider = is.FrameProvider(vie_encoder);
      if (provider) {
        provider->DeregisterFrameCallback(vie_encoder);
      }
    }
  }

  if (shared_data_.channel_manager()->DeleteChannel(video_channel) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not delete channel %d", __FUNCTION__,
                 video_channel);
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel deleted: %d", __FUNCTION__, video_channel);
  return 0;
}

int ViEBaseImpl::ConnectAudioChannel(const int video_channel,
                                     const int audio_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(video_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->ConnectVoiceChannel(video_channel,
                                                          audio_channel) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::DisconnectAudioChannel(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(video_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->DisconnectVoiceChannel(
      video_channel) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StartSend(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  assert(vie_encoder != NULL);
  if (vie_encoder->Owner() != video_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "Can't start ssend on a receive only channel.");
    shared_data_.SetLastError(kViEBaseReceiveOnlyChannel);
    return -1;
  }

  // Pause and trigger a key frame.
  vie_encoder->Pause();
  int32_t error = vie_channel->StartSend();
  if (error != 0) {
    vie_encoder->Restart();
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Could not start sending on channel %d", __FUNCTION__,
                 video_channel);
    if (error == kViEBaseAlreadySending) {
      shared_data_.SetLastError(kViEBaseAlreadySending);
    }
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  vie_encoder->SendKeyFrame();
  vie_encoder->Restart();
  return 0;
}

int ViEBaseImpl::StopSend(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  int32_t error = vie_channel->StopSend();
  if (error != 0) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Could not stop sending on channel %d", __FUNCTION__,
                 video_channel);
    if (error == kViEBaseNotSending) {
      shared_data_.SetLastError(kViEBaseNotSending);
    } else {
      shared_data_.SetLastError(kViEBaseUnknownError);
    }
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StartReceive(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }
  if (vie_channel->StartReceive() != 0) {
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StopReceive(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }
  if (vie_channel->StopReceive() != 0) {
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::GetVersion(char version[1024]) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "GetVersion(version=?)");
  assert(kViEVersionMaxMessageSize == 1024);
  if (!version) {
    shared_data_.SetLastError(kViEBaseInvalidArgument);
    return -1;
  }

  // Add WebRTC Version.
  std::stringstream version_stream;
  version_stream << "VideoEngine 3.34.0" << std::endl;

  // Add build info.
  version_stream << "Build: svn:" << WEBRTC_SVNREVISION << " " << BUILDINFO
                 << std::endl;

#ifdef WEBRTC_EXTERNAL_TRANSPORT
  version_stream << "External transport build" << std::endl;
#endif
  int version_length = version_stream.tellp();
  assert(version_length < 1024);
  memcpy(version, version_stream.str().c_str(), version_length);
  version[version_length] = '\0';

  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo,
               ViEId(shared_data_.instance_id()), "GetVersion() => %s",
               version);
  return 0;
}

int ViEBaseImpl::LastError() {
  return shared_data_.LastErrorInternal();
}

int ViEBaseImpl::CreateChannel(int& video_channel,  // NOLINT
                               int original_channel, bool sender) {
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(original_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s - original_channel does not exist.", __FUNCTION__,
                 shared_data_.instance_id());
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->CreateChannel(&video_channel,
                                                    original_channel,
                                                    sender) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not create channel", __FUNCTION__);
    video_channel = -1;
    shared_data_.SetLastError(kViEBaseChannelCreationFailed);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel created: %d", __FUNCTION__, video_channel);
  return 0;
}

}  // namespace webrtc
<|endoftext|>


<commit_before>
#include <boost/test/unit_test.hpp>

#include "Werk/OS/Hardware.hpp"

BOOST_AUTO_TEST_SUITE(HardwareTest)

BOOST_AUTO_TEST_CASE(TestGetPageSize)
{
	uint64_t pageSize = werk::getPageSize();

	//Anything less than 4K won't be adequate anyway
	BOOST_REQUIRE(pageSize >= 4 * 1024);

	//And memory should come in at least 1K chunks
	BOOST_CHECK_EQUAL(pageSize % 1024, 0);
}

BOOST_AUTO_TEST_CASE(TestGetPhysicalMemorySize)
{
	size_t memorySize = werk::getPhysicalMemorySize();

	//Anything less than 64M won't be adequate anyway
	BOOST_REQUIRE(memorySize >= 64 * 1024 * 1024);

	//And memory should come in at least 1M chunks
	BOOST_CHECK_EQUAL(memorySize % (1024 * 1024), 0);
}

BOOST_AUTO_TEST_CASE(TestGetProcessorCount)
{
	size_t processorCount = werk::getProcessorCount();
	BOOST_REQUIRE(processorCount >= 1);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Modify memory tests to be more robust on different systems<commit_after>
#include <boost/test/unit_test.hpp>

#include "Werk/OS/Hardware.hpp"

BOOST_AUTO_TEST_SUITE(HardwareTest)

BOOST_AUTO_TEST_CASE(TestGetPageSize)
{
	uint64_t pageSize = werk::getPageSize();

	//Anything less than 4K won't be adequate anyway
	BOOST_REQUIRE(pageSize >= 4 * 1024);

	//And pages should come in at least 1K chunks
	BOOST_CHECK_EQUAL(pageSize % 1024, 0);
}

BOOST_AUTO_TEST_CASE(TestGetPhysicalMemorySize)
{
	size_t memorySize = werk::getPhysicalMemorySize();

	//Anything less than 64M won't be adequate anyway
	BOOST_REQUIRE(memorySize >= 64 * 1024 * 1024);

	//And memory should come in at least 1K chunks
	BOOST_CHECK_EQUAL(memorySize % 1024, 0);
}

BOOST_AUTO_TEST_CASE(TestGetProcessorCount)
{
	size_t processorCount = werk::getProcessorCount();
	BOOST_REQUIRE(processorCount >= 1);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/vk/GrVkTexture.h"

#include "src/gpu/GrTexturePriv.h"
#include "src/gpu/vk/GrVkDescriptorSet.h"
#include "src/gpu/vk/GrVkGpu.h"
#include "src/gpu/vk/GrVkImageView.h"
#include "src/gpu/vk/GrVkTextureRenderTarget.h"
#include "src/gpu/vk/GrVkUtil.h"

#include "include/gpu/vk/GrVkTypes.h"

#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)

// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                         SkBudgeted budgeted,
                         SkISize dimensions,
                         const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout,
                         const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kOwned)
        , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    // We don't support creating external GrVkTextures
    SkASSERT(!info.fYcbcrConversionInfo.isValid() || !info.fYcbcrConversionInfo.fExternalFormat);
    this->registerWithCache(budgeted);
    if (GrVkFormatIsCompressed(info.fFormat)) {
        this->setReadOnly();
    }
}

GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout, const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership,
                         GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, std::move(layout), ownership)
        , INHERITED(gpu, dimensions, info.fProtected,
                    isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    if (ioType == kRead_GrIOType) {
        this->setReadOnly();
    }
    this->registerWithCacheWrapped(cacheable);
}

// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                         SkISize dimensions,
                         const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout,
                         const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus,
                         GrBackendObjectOwnership ownership)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, layout, ownership)
        , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion
    // since we don't support that on render targets.
    SkASSERT(!info.fYcbcrConversionInfo.isValid());
}

sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
                                               SkISize dimensions,
                                               const GrVkImage::ImageDesc& imageDesc,
                                               GrMipMapsStatus mipMapsStatus) {
    SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);

    GrVkImageInfo info;
    if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
        return nullptr;
    }

    const GrVkImageView* imageView = GrVkImageView::Create(
            gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
            info.fYcbcrConversionInfo);
    if (!imageView) {
        GrVkImage::DestroyImageInfo(gpu, &info);
        return nullptr;
    }
    sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));

    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, std::move(layout),
                                              imageView, mipMapsStatus));
}

sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
                                                   SkISize dimensions,
                                                   GrWrapOwnership wrapOwnership,
                                                   GrWrapCacheable cacheable,
                                                   GrIOType ioType,
                                                   const GrVkImageInfo& info,
                                                   sk_sp<GrVkImageLayout> layout) {
    // Adopted textures require both image and allocation because we're responsible for freeing
    SkASSERT(VK_NULL_HANDLE != info.fImage &&
             (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));

    const GrVkImageView* imageView = GrVkImageView::Create(
            gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
            info.fYcbcrConversionInfo);
    if (!imageView) {
        return nullptr;
    }

    GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
                                                         : GrMipMapsStatus::kNotAllocated;

    GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
            ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
    bool isExternal = info.fYcbcrConversionInfo.isValid() &&
                      (info.fYcbcrConversionInfo.fExternalFormat != 0);
    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(layout), imageView,
                                              mipMapsStatus, ownership, cacheable, ioType,
                                              isExternal));
}

GrVkTexture::~GrVkTexture() {
    // either release or abandon should have been called by the owner of this object.
    SkASSERT(!fTextureView);
}

void GrVkTexture::onRelease() {
    // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
    // decide who will handle them. If the resource is still tied to a command buffer we let it
    // handle them. Otherwise, we handle them.
    if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
        this->removeFinishIdleProcs();
    }

    // we create this and don't hand it off, so we should always destroy it
    if (fTextureView) {
        fTextureView->unref(this->getVkGpu());
        fTextureView = nullptr;
    }

    fDescSetCache.reset();

    this->releaseImage(this->getVkGpu());

    INHERITED::onRelease();
}

struct GrVkTexture::DescriptorCacheEntry {
    DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
            : fDescriptorSet(fDescSet), fGpu(gpu) {}
    ~DescriptorCacheEntry() {
        if (fDescriptorSet) {
            fDescriptorSet->recycle(fGpu);
        }
    }

    const GrVkDescriptorSet* fDescriptorSet;
    GrVkGpu* fGpu;
};

void GrVkTexture::onAbandon() {
    // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
    // decide who will handle them. If the resource is still tied to a command buffer we let it
    // handle them. Otherwise, we handle them.
    if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
        this->removeFinishIdleProcs();
    }

    // we create this and don't hand it off, so we should always destroy it
    if (fTextureView) {
        fTextureView->unref(this->getVkGpu());
        fTextureView = nullptr;
    }

    fDescSetCache.reset();

    this->releaseImage(this->getVkGpu());
    INHERITED::onAbandon();
}

GrBackendTexture GrVkTexture::getBackendTexture() const {
    return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
}

GrVkGpu* GrVkTexture::getVkGpu() const {
    SkASSERT(!this->wasDestroyed());
    return static_cast<GrVkGpu*>(this->getGpu());
}

const GrVkImageView* GrVkTexture::textureView() {
    return fTextureView;
}

void GrVkTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc, IdleState type) {
    INHERITED::addIdleProc(idleProc, type);
    if (type == IdleState::kFinished) {
        if (auto* resource = this->resource()) {
            resource->addIdleProc(this, std::move(idleProc));
        }
    }
}

void GrVkTexture::callIdleProcsOnBehalfOfResource() {
    // If we got here then the resource is being removed from its last command buffer and the
    // texture is idle in the cache. Any kFlush idle procs should already have been called. So
    // the texture and resource should have the same set of procs.
    SkASSERT(this->resource());
    SkASSERT(this->resource()->idleProcCnt() == fIdleProcs.count());
#ifdef SK_DEBUG
    for (int i = 0; i < fIdleProcs.count(); ++i) {
        SkASSERT(fIdleProcs[i] == this->resource()->idleProc(i));
    }
#endif
    fIdleProcs.reset();
    this->resource()->resetIdleProcs();
}

void GrVkTexture::willRemoveLastRef() {
    if (!fIdleProcs.count()) {
        return;
    }
    // This is called when the GrTexture is purgeable. However, we need to check whether the
    // Resource is still owned by any command buffers. If it is then it will call the proc.
    auto* resource = this->hasResource() ? this->resource() : nullptr;
    bool callFinishProcs = !resource || !resource->isOwnedByCommandBuffer();
    if (callFinishProcs) {
        // Everything must go!
        fIdleProcs.reset();
        resource->resetIdleProcs();
    } else {
        // The procs that should be called on flush but not finish are those that are owned
        // by the GrVkTexture and not the Resource. We do this by copying the resource's array
        // and thereby dropping refs to procs we own but the resource does not.
        SkASSERT(resource);
        fIdleProcs.reset(resource->idleProcCnt());
        for (int i = 0; i < fIdleProcs.count(); ++i) {
            fIdleProcs[i] = resource->idleProc(i);
        }
    }
}

void GrVkTexture::removeFinishIdleProcs() {
    // This should only be called by onRelease/onAbandon when we have already checked for a
    // resource.
    const auto* resource = this->resource();
    SkASSERT(resource);
    SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
    int resourceIdx = 0;
    // The idle procs that are common between the GrVkTexture and its Resource should be found in
    // the same order.
    for (int i = 0; i < fIdleProcs.count(); ++i) {
        if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
            ++resourceIdx;
        } else {
            procsToKeep.push_back(fIdleProcs[i]);
        }
    }
    SkASSERT(resourceIdx == resource->idleProcCnt());
    fIdleProcs = procsToKeep;
}

const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
    if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
        return (*e)->fDescriptorSet;
    }
    return nullptr;
}

void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
    SkASSERT(!fDescSetCache.find(state));
    descSet->ref();
    fDescSetCache.insert(state,
                         std::unique_ptr<DescriptorCacheEntry>(
                                 new DescriptorCacheEntry(descSet, this->getVkGpu())));
}
<commit_msg>Avoid possible nullptr dereference am: e26a98217e am: f6cc75d713<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/vk/GrVkTexture.h"

#include "src/gpu/GrTexturePriv.h"
#include "src/gpu/vk/GrVkDescriptorSet.h"
#include "src/gpu/vk/GrVkGpu.h"
#include "src/gpu/vk/GrVkImageView.h"
#include "src/gpu/vk/GrVkTextureRenderTarget.h"
#include "src/gpu/vk/GrVkUtil.h"

#include "include/gpu/vk/GrVkTypes.h"

#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)

// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                         SkBudgeted budgeted,
                         SkISize dimensions,
                         const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout,
                         const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kOwned)
        , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    // We don't support creating external GrVkTextures
    SkASSERT(!info.fYcbcrConversionInfo.isValid() || !info.fYcbcrConversionInfo.fExternalFormat);
    this->registerWithCache(budgeted);
    if (GrVkFormatIsCompressed(info.fFormat)) {
        this->setReadOnly();
    }
}

GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout, const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership,
                         GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, std::move(layout), ownership)
        , INHERITED(gpu, dimensions, info.fProtected,
                    isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    if (ioType == kRead_GrIOType) {
        this->setReadOnly();
    }
    this->registerWithCacheWrapped(cacheable);
}

// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                         SkISize dimensions,
                         const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout,
                         const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus,
                         GrBackendObjectOwnership ownership)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, layout, ownership)
        , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion
    // since we don't support that on render targets.
    SkASSERT(!info.fYcbcrConversionInfo.isValid());
}

sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
                                               SkISize dimensions,
                                               const GrVkImage::ImageDesc& imageDesc,
                                               GrMipMapsStatus mipMapsStatus) {
    SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);

    GrVkImageInfo info;
    if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
        return nullptr;
    }

    const GrVkImageView* imageView = GrVkImageView::Create(
            gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
            info.fYcbcrConversionInfo);
    if (!imageView) {
        GrVkImage::DestroyImageInfo(gpu, &info);
        return nullptr;
    }
    sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));

    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, std::move(layout),
                                              imageView, mipMapsStatus));
}

sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
                                                   SkISize dimensions,
                                                   GrWrapOwnership wrapOwnership,
                                                   GrWrapCacheable cacheable,
                                                   GrIOType ioType,
                                                   const GrVkImageInfo& info,
                                                   sk_sp<GrVkImageLayout> layout) {
    // Adopted textures require both image and allocation because we're responsible for freeing
    SkASSERT(VK_NULL_HANDLE != info.fImage &&
             (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));

    const GrVkImageView* imageView = GrVkImageView::Create(
            gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
            info.fYcbcrConversionInfo);
    if (!imageView) {
        return nullptr;
    }

    GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
                                                         : GrMipMapsStatus::kNotAllocated;

    GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
            ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
    bool isExternal = info.fYcbcrConversionInfo.isValid() &&
                      (info.fYcbcrConversionInfo.fExternalFormat != 0);
    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(layout), imageView,
                                              mipMapsStatus, ownership, cacheable, ioType,
                                              isExternal));
}

GrVkTexture::~GrVkTexture() {
    // either release or abandon should have been called by the owner of this object.
    SkASSERT(!fTextureView);
}

void GrVkTexture::onRelease() {
    // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
    // decide who will handle them. If the resource is still tied to a command buffer we let it
    // handle them. Otherwise, we handle them.
    if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
        this->removeFinishIdleProcs();
    }

    // we create this and don't hand it off, so we should always destroy it
    if (fTextureView) {
        fTextureView->unref(this->getVkGpu());
        fTextureView = nullptr;
    }

    fDescSetCache.reset();

    this->releaseImage(this->getVkGpu());

    INHERITED::onRelease();
}

struct GrVkTexture::DescriptorCacheEntry {
    DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
            : fDescriptorSet(fDescSet), fGpu(gpu) {}
    ~DescriptorCacheEntry() {
        if (fDescriptorSet) {
            fDescriptorSet->recycle(fGpu);
        }
    }

    const GrVkDescriptorSet* fDescriptorSet;
    GrVkGpu* fGpu;
};

void GrVkTexture::onAbandon() {
    // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
    // decide who will handle them. If the resource is still tied to a command buffer we let it
    // handle them. Otherwise, we handle them.
    if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
        this->removeFinishIdleProcs();
    }

    // we create this and don't hand it off, so we should always destroy it
    if (fTextureView) {
        fTextureView->unref(this->getVkGpu());
        fTextureView = nullptr;
    }

    fDescSetCache.reset();

    this->releaseImage(this->getVkGpu());
    INHERITED::onAbandon();
}

GrBackendTexture GrVkTexture::getBackendTexture() const {
    return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
}

GrVkGpu* GrVkTexture::getVkGpu() const {
    SkASSERT(!this->wasDestroyed());
    return static_cast<GrVkGpu*>(this->getGpu());
}

const GrVkImageView* GrVkTexture::textureView() {
    return fTextureView;
}

void GrVkTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc, IdleState type) {
    INHERITED::addIdleProc(idleProc, type);
    if (type == IdleState::kFinished) {
        if (auto* resource = this->resource()) {
            resource->addIdleProc(this, std::move(idleProc));
        }
    }
}

void GrVkTexture::callIdleProcsOnBehalfOfResource() {
    // If we got here then the resource is being removed from its last command buffer and the
    // texture is idle in the cache. Any kFlush idle procs should already have been called. So
    // the texture and resource should have the same set of procs.
    SkASSERT(this->resource());
    SkASSERT(this->resource()->idleProcCnt() == fIdleProcs.count());
#ifdef SK_DEBUG
    for (int i = 0; i < fIdleProcs.count(); ++i) {
        SkASSERT(fIdleProcs[i] == this->resource()->idleProc(i));
    }
#endif
    fIdleProcs.reset();
    this->resource()->resetIdleProcs();
}

void GrVkTexture::willRemoveLastRef() {
    if (!fIdleProcs.count()) {
        return;
    }
    // This is called when the GrTexture is purgeable. However, we need to check whether the
    // Resource is still owned by any command buffers. If it is then it will call the proc.
    auto* resource = this->hasResource() ? this->resource() : nullptr;
    bool callFinishProcs = !resource || !resource->isOwnedByCommandBuffer();
    if (callFinishProcs) {
        // Everything must go!
        fIdleProcs.reset();
        if (resource) {
            resource->resetIdleProcs();
        }
    } else {
        // The procs that should be called on flush but not finish are those that are owned
        // by the GrVkTexture and not the Resource. We do this by copying the resource's array
        // and thereby dropping refs to procs we own but the resource does not.
        SkASSERT(resource);
        fIdleProcs.reset(resource->idleProcCnt());
        for (int i = 0; i < fIdleProcs.count(); ++i) {
            fIdleProcs[i] = resource->idleProc(i);
        }
    }
}

void GrVkTexture::removeFinishIdleProcs() {
    // This should only be called by onRelease/onAbandon when we have already checked for a
    // resource.
    const auto* resource = this->resource();
    SkASSERT(resource);
    SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
    int resourceIdx = 0;
    // The idle procs that are common between the GrVkTexture and its Resource should be found in
    // the same order.
    for (int i = 0; i < fIdleProcs.count(); ++i) {
        if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
            ++resourceIdx;
        } else {
            procsToKeep.push_back(fIdleProcs[i]);
        }
    }
    SkASSERT(resourceIdx == resource->idleProcCnt());
    fIdleProcs = procsToKeep;
}

const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
    if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
        return (*e)->fDescriptorSet;
    }
    return nullptr;
}

void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
    SkASSERT(!fDescSetCache.find(state));
    descSet->ref();
    fDescSetCache.insert(state,
                         std::unique_ptr<DescriptorCacheEntry>(
                                 new DescriptorCacheEntry(descSet, this->getVkGpu())));
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgGA/SimpleViewer>
#include <osgGA/TrackballManipulator>

using namespace osgGA;

SimpleViewer::SimpleViewer():
    _firstFrame(true)
{
    _sceneView = new osgUtil::SceneView;
    _sceneView->setDefaults();
    _sceneView->getState()->setContextID(osg::GraphicsContext::createNewContextID());

    _startTick = osg::Timer::instance()->tick();
    _frameStamp = new osg::FrameStamp;
    _frameStamp->setFrameNumber(0);
    _frameStamp->setReferenceTime(0);

    _eventQueue = new osgGA::EventQueue;
    _eventQueue->setStartTick(_startTick);

    _eventVisitor = new osgGA::EventVisitor;

    setDatabasePager(new osgDB::DatabasePager);
}

SimpleViewer::~SimpleViewer()
{
    _sceneView->releaseAllGLObjects();
    osg::GraphicsContext::decrementContextIDUsageCount(_sceneView->getState()->getContextID());
}

void SimpleViewer::setSceneData(osg::Node* node)
{
    _sceneView->setSceneData(node);

    if (_cameraManipulator.valid())
    {
        _cameraManipulator->setNode(node);

        osg::ref_ptr<osgGA::GUIEventAdapter> dummyEvent = _eventQueue->createEvent();
        _cameraManipulator->home(*dummyEvent, *this);
    }

    if (_databasePager.valid())
    {
        // register any PagedLOD that need to be tracked in the scene graph
        _databasePager->registerPagedLODs(node);
    }
}

osg::Node* SimpleViewer::getSceneData()
{
    return _sceneView->getSceneData();
}

const osg::Node* SimpleViewer::getSceneData() const
{
    return _sceneView->getSceneData();
}

osg::CameraNode* SimpleViewer::getCamera()
{
    return _sceneView->getCamera();
}

const osg::CameraNode* SimpleViewer::getCamera() const
{
    return _sceneView->getCamera();
}

void SimpleViewer::setCameraManipulator(MatrixManipulator* manipulator)
{
    if (_cameraManipulator == manipulator) return;

    _cameraManipulator = manipulator;
    if (_cameraManipulator.valid())
    {
        _cameraManipulator->setNode(_sceneView->getSceneData());

        osg::ref_ptr<osgGA::GUIEventAdapter> dummyEvent = _eventQueue->createEvent();
        _cameraManipulator->home(*dummyEvent, *this);
    }
}

void SimpleViewer::addEventHandler(GUIEventHandler* eventHandler)
{
    _eventHandlers.push_back(eventHandler);
}

void SimpleViewer::setDatabasePager(osgDB::DatabasePager* dp)
{
    _databasePager = dp;

    if (dp && _sceneView.valid())
    {
        // need to register the DatabasePager with the SceneView's CullVisitor so it can pass on request
        // for files to be loaded.
        _sceneView->getCullVisitor()->setDatabaseRequestHandler(_databasePager.get());
    }
}

void SimpleViewer::init()
{
    osg::ref_ptr<osgGA::GUIEventAdapter> initEvent = _eventQueue->createEvent();
    initEvent->setEventType(osgGA::GUIEventAdapter::FRAME);
    _cameraManipulator->init(*initEvent, *this);
}

void SimpleViewer::frame()
{
    if (_firstFrame)
    {
        init();
        _firstFrame = false;
    }

    frameAdvance();
    frameEventTraversal();
    frameUpdateTraversal();
    frameCullTraversal();
    frameDrawTraversal();
}

void SimpleViewer::frameAdvance()
{
    osg::Timer_t currentTick  = osg::Timer::instance()->tick();
    _frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(_startTick,currentTick));
    _frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1);

    _sceneView->setFrameStamp(_frameStamp.get());
}

void SimpleViewer::frameEventTraversal()
{
    _eventQueue->frame( _frameStamp->getReferenceTime() );

    osgGA::EventQueue::Events events;
    _eventQueue->takeEvents(events);

    if (_eventVisitor.valid())
    {
        _eventVisitor->setTraversalNumber(_frameStamp->getFrameNumber());
    }

    for(osgGA::EventQueue::Events::iterator itr = events.begin();
        itr != events.end();
        ++itr)
    {
        osgGA::GUIEventAdapter* event = itr->get();

        bool handled = false;

        if (_eventVisitor.valid())
        {
            _eventVisitor->reset();
            _eventVisitor->addEvent( event );

            getSceneData()->accept(*_eventVisitor);

            if (_eventVisitor->getEventHandled())  handled = true;
        }

        if (_cameraManipulator.valid())
        {
            _cameraManipulator->handle( *event, *this );
        }

        for(EventHandlers::iterator hitr = _eventHandlers.begin();
            hitr != _eventHandlers.end() && !handled;
            ++hitr)
        {
            handled = (*hitr)->handle( *event, *this, 0, 0);
        }
    }
}

void SimpleViewer::frameUpdateTraversal()
{
    double previousAspectRatio = ( static_cast<double>(_sceneView->getViewport()->width())/
                                   static_cast<double>(_sceneView->getViewport()->height()) );

    // update the viewport
    int width = _eventQueue->getCurrentEventState()->getWindowWidth();
    int height = _eventQueue->getCurrentEventState()->getWindowHeight();
    _sceneView->setViewport(0,0,width,height);

    double newAspectRatio = ( static_cast<double>(_sceneView->getViewport()->width())/
                              static_cast<double>(_sceneView->getViewport()->height()) );

    // if aspect ratio adjusted change the project matrix to suit.
    if (previousAspectRatio != newAspectRatio)
    {
        osg::Matrixd& pm = _sceneView->getProjectionMatrix();
        bool orthographicCamera = (pm(0,3)==0.0) && (pm(0,3)==0.0) && (pm(0,3)==0.0) && (pm(0,3)==1.0);
        if (orthographicCamera)
        {
            double left, right, bottom, top, zNear, zFar;
            _sceneView->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);

            double mid = (right+left)*0.5;
            double halfWidth = (right-left)*0.5;
            left = mid - halfWidth * (newAspectRatio/previousAspectRatio);
            right = mid + halfWidth * (newAspectRatio/previousAspectRatio);
            _sceneView->setProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);
        }
        else
        {
            double left, right, bottom, top, zNear, zFar;
            _sceneView->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);

            double mid = (right+left)*0.5;
            double halfWidth = (right-left)*0.5;
            left = mid - halfWidth * (newAspectRatio/previousAspectRatio);
            right = mid + halfWidth * (newAspectRatio/previousAspectRatio);
            _sceneView->setProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
        }
    }

    if (_cameraManipulator.valid())
    {
        _sceneView->setViewMatrix(_cameraManipulator->getInverseMatrix());
    }

    if (_databasePager.valid())
    {
        // tell the DatabasePager the frame number of that the scene graph is being actively used to render a frame
        _databasePager->signalBeginFrame(_frameStamp.get());

        // syncronize changes required by the DatabasePager thread to the scene graph
        _databasePager->updateSceneGraph(_frameStamp->getReferenceTime());
    }

    _sceneView->update();
}

void SimpleViewer::frameCullTraversal()
{
    _sceneView->cull();
}

void SimpleViewer::frameDrawTraversal()
{
    _sceneView->draw();

    if (_databasePager.valid())
    {
        // tell the DatabasePager the frame number of that the scene graph is being actively used to render a frame
        _databasePager->signalEndFrame();

        // clean up  and compile gl objects with a specified limit
        double availableTime = 0.0025; // 2.5 ms

        // compile any GL objects that are required.
        _databasePager->compileGLObjects(*(_sceneView->getState()),availableTime);

        // flush deleted GL objects.
        _sceneView->flushDeletedGLObjects(availableTime);
    }
}

void SimpleViewer::cleanup()
{
    if (_databasePager.valid())
    {
        // clear the database pager so its starts a fresh on the next update/cull/draw traversals
        _databasePager->clear();

        // release the GL objects stored in the scene graph.
        _sceneView->releaseAllGLObjects();

        // do a flush to delete all the OpenGL objects that have been deleted or released from the scene graph.
        _sceneView->flushAllDeletedGLObjects();
    }

    _sceneView->releaseAllGLObjects();
    _sceneView->flushAllDeletedGLObjects();
}
<commit_msg>Added check to init to prevent crash when no camera manipulator is supplied.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgGA/SimpleViewer>
#include <osgGA/TrackballManipulator>

using namespace osgGA;

SimpleViewer::SimpleViewer():
    _firstFrame(true)
{
    _sceneView = new osgUtil::SceneView;
    _sceneView->setDefaults();
    _sceneView->getState()->setContextID(osg::GraphicsContext::createNewContextID());

    _startTick = osg::Timer::instance()->tick();
    _frameStamp = new osg::FrameStamp;
    _frameStamp->setFrameNumber(0);
    _frameStamp->setReferenceTime(0);

    _eventQueue = new osgGA::EventQueue;
    _eventQueue->setStartTick(_startTick);

    _eventVisitor = new osgGA::EventVisitor;

    setDatabasePager(new osgDB::DatabasePager);
}

SimpleViewer::~SimpleViewer()
{
    _sceneView->releaseAllGLObjects();
    osg::GraphicsContext::decrementContextIDUsageCount(_sceneView->getState()->getContextID());
}

void SimpleViewer::setSceneData(osg::Node* node)
{
    _sceneView->setSceneData(node);

    if (_cameraManipulator.valid())
    {
        _cameraManipulator->setNode(node);

        osg::ref_ptr<osgGA::GUIEventAdapter> dummyEvent = _eventQueue->createEvent();
        _cameraManipulator->home(*dummyEvent, *this);
    }

    if (_databasePager.valid())
    {
        // register any PagedLOD that need to be tracked in the scene graph
        _databasePager->registerPagedLODs(node);
    }
}

osg::Node* SimpleViewer::getSceneData()
{
    return _sceneView->getSceneData();
}

const osg::Node* SimpleViewer::getSceneData() const
{
    return _sceneView->getSceneData();
}

osg::CameraNode* SimpleViewer::getCamera()
{
    return _sceneView->getCamera();
}

const osg::CameraNode* SimpleViewer::getCamera() const
{
    return _sceneView->getCamera();
}

void SimpleViewer::setCameraManipulator(MatrixManipulator* manipulator)
{
    if (_cameraManipulator == manipulator) return;

    _cameraManipulator = manipulator;
    if (_cameraManipulator.valid())
    {
        _cameraManipulator->setNode(_sceneView->getSceneData());

        osg::ref_ptr<osgGA::GUIEventAdapter> dummyEvent = _eventQueue->createEvent();
        _cameraManipulator->home(*dummyEvent, *this);
    }
}

void SimpleViewer::addEventHandler(GUIEventHandler* eventHandler)
{
    _eventHandlers.push_back(eventHandler);
}

void SimpleViewer::setDatabasePager(osgDB::DatabasePager* dp)
{
    _databasePager = dp;

    if (dp && _sceneView.valid())
    {
        // need to register the DatabasePager with the SceneView's CullVisitor so it can pass on request
        // for files to be loaded.
        _sceneView->getCullVisitor()->setDatabaseRequestHandler(_databasePager.get());
    }
}

void SimpleViewer::init()
{
    osg::ref_ptr<osgGA::GUIEventAdapter> initEvent = _eventQueue->createEvent();
    initEvent->setEventType(osgGA::GUIEventAdapter::FRAME);

    if (_cameraManipulator.valid())
    {
        _cameraManipulator->init(*initEvent, *this);
    }
}

void SimpleViewer::frame()
{
    if (_firstFrame)
    {
        init();
        _firstFrame = false;
    }

    frameAdvance();
    frameEventTraversal();
    frameUpdateTraversal();
    frameCullTraversal();
    frameDrawTraversal();
}

void SimpleViewer::frameAdvance()
{
    osg::Timer_t currentTick  = osg::Timer::instance()->tick();
    _frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(_startTick,currentTick));
    _frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1);

    _sceneView->setFrameStamp(_frameStamp.get());
}

void SimpleViewer::frameEventTraversal()
{
    _eventQueue->frame( _frameStamp->getReferenceTime() );

    osgGA::EventQueue::Events events;
    _eventQueue->takeEvents(events);

    if (_eventVisitor.valid())
    {
        _eventVisitor->setTraversalNumber(_frameStamp->getFrameNumber());
    }

    for(osgGA::EventQueue::Events::iterator itr = events.begin();
        itr != events.end();
        ++itr)
    {
        osgGA::GUIEventAdapter* event = itr->get();

        bool handled = false;

        if (_eventVisitor.valid())
        {
            _eventVisitor->reset();
            _eventVisitor->addEvent( event );

            getSceneData()->accept(*_eventVisitor);

            if (_eventVisitor->getEventHandled())  handled = true;
        }

        if (_cameraManipulator.valid())
        {
            _cameraManipulator->handle( *event, *this );
        }

        for(EventHandlers::iterator hitr = _eventHandlers.begin();
            hitr != _eventHandlers.end() && !handled;
            ++hitr)
        {
            handled = (*hitr)->handle( *event, *this, 0, 0);
        }
    }
}

void SimpleViewer::frameUpdateTraversal()
{
    double previousAspectRatio = ( static_cast<double>(_sceneView->getViewport()->width())/
                                   static_cast<double>(_sceneView->getViewport()->height()) );

    // update the viewport
    int width = _eventQueue->getCurrentEventState()->getWindowWidth();
    int height = _eventQueue->getCurrentEventState()->getWindowHeight();
    _sceneView->setViewport(0,0,width,height);

    double newAspectRatio = ( static_cast<double>(_sceneView->getViewport()->width())/
                              static_cast<double>(_sceneView->getViewport()->height()) );

    // if aspect ratio adjusted change the project matrix to suit.
    if (previousAspectRatio != newAspectRatio)
    {
        osg::Matrixd& pm = _sceneView->getProjectionMatrix();
        bool orthographicCamera = (pm(0,3)==0.0) && (pm(0,3)==0.0) && (pm(0,3)==0.0) && (pm(0,3)==1.0);
        if (orthographicCamera)
        {
            double left, right, bottom, top, zNear, zFar;
            _sceneView->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);

            double mid = (right+left)*0.5;
            double halfWidth = (right-left)*0.5;
            left = mid - halfWidth * (newAspectRatio/previousAspectRatio);
            right = mid + halfWidth * (newAspectRatio/previousAspectRatio);
            _sceneView->setProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);
        }
        else
        {
            double left, right, bottom, top, zNear, zFar;
            _sceneView->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);

            double mid = (right+left)*0.5;
            double halfWidth = (right-left)*0.5;
            left = mid - halfWidth * (newAspectRatio/previousAspectRatio);
            right = mid + halfWidth * (newAspectRatio/previousAspectRatio);
            _sceneView->setProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
        }
    }

    if (_cameraManipulator.valid())
    {
        _sceneView->setViewMatrix(_cameraManipulator->getInverseMatrix());
    }

    if (_databasePager.valid())
    {
        // tell the DatabasePager the frame number of that the scene graph is being actively used to render a frame
        _databasePager->signalBeginFrame(_frameStamp.get());

        // syncronize changes required by the DatabasePager thread to the scene graph
        _databasePager->updateSceneGraph(_frameStamp->getReferenceTime());
    }

    _sceneView->update();
}

void SimpleViewer::frameCullTraversal()
{
    _sceneView->cull();
}

void SimpleViewer::frameDrawTraversal()
{
    _sceneView->draw();

    if (_databasePager.valid())
    {
        // tell the DatabasePager the frame number of that the scene graph is being actively used to render a frame
        _databasePager->signalEndFrame();

        // clean up  and compile gl objects with a specified limit
        double availableTime = 0.0025; // 2.5 ms

        // compile any GL objects that are required.
        _databasePager->compileGLObjects(*(_sceneView->getState()),availableTime);

        // flush deleted GL objects.
        _sceneView->flushDeletedGLObjects(availableTime);
    }
}

void SimpleViewer::cleanup()
{
    if (_databasePager.valid())
    {
        // clear the database pager so its starts a fresh on the next update/cull/draw traversals
        _databasePager->clear();

        // release the GL objects stored in the scene graph.
        _sceneView->releaseAllGLObjects();

        // do a flush to delete all the OpenGL objects that have been deleted or released from the scene graph.
        _sceneView->flushAllDeletedGLObjects();
    }

    _sceneView->releaseAllGLObjects();
    _sceneView->flushAllDeletedGLObjects();
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osgUtil/RenderLeaf>
#include <osgUtil/RenderGraph>

using namespace osg;
using namespace osgUtil;

// comment if you are are working with vertex programs,
// but it does break osgreflect demo and perhaps others, so keep an eye
// out artifacts.
// #define APPLY_MATICES_BEFORE_STATE

void RenderLeaf::render(State& state,RenderLeaf* previous)
{

    if (previous)
    {

#ifdef APPLY_MATICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif
        // apply state if required.
        RenderGraph* prev_rg = previous->_parent;
        RenderGraph* prev_rg_parent = prev_rg->_parent;
        RenderGraph* rg = _parent;
        if (prev_rg_parent!=rg->_parent)
        {
            RenderGraph::moveRenderGraph(state,prev_rg_parent,rg->_parent);

            // send state changes and matrix changes to OpenGL.
            state.apply(rg->_stateset.get());

        }
        else if (rg!=prev_rg)
        {

            // send state changes and matrix changes to OpenGL.
            state.apply(rg->_stateset.get());

        }

#ifndef APPLY_MATICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // draw the drawable
        _drawable->draw(state);
    }
    else
    {
#ifdef APPLY_MATICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // apply state if required.
         RenderGraph::moveRenderGraph(state,NULL,_parent->_parent);

        state.apply(_parent->_stateset.get());

#ifndef APPLY_MATICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // draw the drawable
        _drawable->draw(state);
    }
}
<commit_msg>Fixed typo of APPLY_MATICES_BEFORE_STATE.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osgUtil/RenderLeaf>
#include <osgUtil/RenderGraph>

using namespace osg;
using namespace osgUtil;

// comment if you are are working with vertex programs,
// but it does break osgreflect demo and perhaps others, so keep an eye
// out artifacts.
// #define APPLY_MATRICES_BEFORE_STATE

void RenderLeaf::render(State& state,RenderLeaf* previous)
{

    if (previous)
    {

#ifdef APPLY_MATRICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif
        // apply state if required.
        RenderGraph* prev_rg = previous->_parent;
        RenderGraph* prev_rg_parent = prev_rg->_parent;
        RenderGraph* rg = _parent;
        if (prev_rg_parent!=rg->_parent)
        {
            RenderGraph::moveRenderGraph(state,prev_rg_parent,rg->_parent);

            // send state changes and matrix changes to OpenGL.
            state.apply(rg->_stateset.get());

        }
        else if (rg!=prev_rg)
        {

            // send state changes and matrix changes to OpenGL.
            state.apply(rg->_stateset.get());

        }

#ifndef APPLY_MATRICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // draw the drawable
        _drawable->draw(state);
    }
    else
    {
#ifdef APPLY_MATRICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // apply state if required.
         RenderGraph::moveRenderGraph(state,NULL,_parent->_parent);

        state.apply(_parent->_stateset.get());

#ifndef APPLY_MATRICES_BEFORE_STATE
        // apply matrices if required.
        state.applyProjectionMatrix(_projection.get());
        state.applyModelViewMatrix(_modelview.get());
#endif

        // draw the drawable
        _drawable->draw(state);
    }
}
<|endoftext|>